Merge branch 'master' of github.com:yoimiya-kokomi/miao-plugin

 Conflicts:
	resources/meta-sr/artifact/meta.json
	resources/meta-sr/character/三月七/data.json
	resources/meta-sr/character/三月七/imgs/splash.webp
	resources/meta-sr/character/丹恒/data.json
	resources/meta-sr/character/丹恒/imgs/splash.webp
	resources/meta-sr/character/佩拉/data.json
	resources/meta-sr/character/佩拉/imgs/splash.webp
	resources/meta-sr/character/停云/data.json
	resources/meta-sr/character/停云/imgs/splash.webp
	resources/meta-sr/character/克拉拉/data.json
	resources/meta-sr/character/克拉拉/imgs/splash.webp
	resources/meta-sr/character/卡芙卡/data.json
	resources/meta-sr/character/卡芙卡/imgs/splash.webp
	resources/meta-sr/character/姬子/data.json
	resources/meta-sr/character/姬子/imgs/splash.webp
	resources/meta-sr/character/娜塔莎/data.json
	resources/meta-sr/character/娜塔莎/imgs/splash.webp
	resources/meta-sr/character/布洛妮娅/data.json
	resources/meta-sr/character/布洛妮娅/imgs/splash.webp
	resources/meta-sr/character/希儿/data.json
	resources/meta-sr/character/希儿/imgs/splash.webp
	resources/meta-sr/character/希露瓦/data.json
	resources/meta-sr/character/希露瓦/imgs/splash.webp
	resources/meta-sr/character/彦卿/data.json
	resources/meta-sr/character/彦卿/imgs/splash.webp
	resources/meta-sr/character/景元/data.json
	resources/meta-sr/character/景元/imgs/splash.webp
	resources/meta-sr/character/杰帕德/data.json
	resources/meta-sr/character/杰帕德/imgs/splash.webp
	resources/meta-sr/character/桑博/data.json
	resources/meta-sr/character/桑博/imgs/splash.webp
	resources/meta-sr/character/瓦尔特/data.json
	resources/meta-sr/character/瓦尔特/imgs/splash.webp
	resources/meta-sr/character/白露/data.json
	resources/meta-sr/character/白露/imgs/splash.webp
	resources/meta-sr/character/素裳/data.json
	resources/meta-sr/character/素裳/imgs/splash.webp
	resources/meta-sr/character/罗刹/data.json
	resources/meta-sr/character/罗刹/imgs/splash.webp
	resources/meta-sr/character/艾丝妲/data.json
	resources/meta-sr/character/艾丝妲/imgs/splash.webp
	resources/meta-sr/character/虎克/data.json
	resources/meta-sr/character/虎克/imgs/splash.webp
	resources/meta-sr/character/银狼/data.json
	resources/meta-sr/character/银狼/imgs/splash.webp
	resources/meta-sr/character/阿兰/data.json
	resources/meta-sr/character/阿兰/imgs/splash.webp
	resources/meta-sr/character/青雀/data.json
	resources/meta-sr/character/青雀/imgs/splash.webp
	resources/meta-sr/character/黑塔/data.json
	resources/meta-sr/character/黑塔/imgs/splash.webp
	resources/meta-sr/weapon/丰饶/一场术后对话/data.json
	resources/meta-sr/weapon/丰饶/同一种心情/data.json
	resources/meta-sr/weapon/丰饶/嘉果/data.json
	resources/meta-sr/weapon/丰饶/时节不居/data.json
	resources/meta-sr/weapon/丰饶/暖夜不会漫长/data.json
	resources/meta-sr/weapon/丰饶/此时恰好/data.json
	resources/meta-sr/weapon/丰饶/物穰/data.json
	resources/meta-sr/weapon/丰饶/等价交换/data.json
	resources/meta-sr/weapon/丰饶/蕃息/data.json
	resources/meta-sr/weapon/同谐/与行星相会/data.json
	resources/meta-sr/weapon/同谐/但战斗还未结束/data.json
	resources/meta-sr/weapon/同谐/舞!舞!舞!/data.json
	resources/meta-sr/weapon/同谐/记忆中的模样/data.json
	resources/meta-sr/weapon/同谐/调和/data.json
	resources/meta-sr/weapon/同谐/轮契/data.json
	resources/meta-sr/weapon/同谐/过往未来/data.json
	resources/meta-sr/weapon/同谐/镂月裁云之意/data.json
	resources/meta-sr/weapon/同谐/齐颂/data.json
	resources/meta-sr/weapon/存护/余生的第一天/data.json
	resources/meta-sr/weapon/存护/制胜的瞬间/data.json
	resources/meta-sr/weapon/存护/宇宙市场趋势/data.json
	resources/meta-sr/weapon/存护/开疆/data.json
	resources/meta-sr/weapon/存护/戍御/data.json
	resources/meta-sr/weapon/存护/我们是地火/data.json
	resources/meta-sr/weapon/存护/朗道的选择/data.json
	resources/meta-sr/weapon/存护/琥珀/data.json
	resources/meta-sr/weapon/存护/记忆的质料/data.json
	resources/meta-sr/weapon/存护/这就是我啦!/data.json
	resources/meta-sr/weapon/巡猎/于夜色中/data.json
	resources/meta-sr/weapon/巡猎/唯有沉默/data.json
	resources/meta-sr/weapon/巡猎/如泥酣眠/data.json
	resources/meta-sr/weapon/巡猎/星海巡航/data.json
	resources/meta-sr/weapon/巡猎/春水初生/data.json
	resources/meta-sr/weapon/巡猎/点个关注吧!/data.json
	resources/meta-sr/weapon/巡猎/相抗/data.json
	resources/meta-sr/weapon/巡猎/离弦/data.json
	resources/meta-sr/weapon/巡猎/论剑/data.json
	resources/meta-sr/weapon/巡猎/重返幽冥/data.json
	resources/meta-sr/weapon/巡猎/锋镝/data.json
	resources/meta-sr/weapon/智识/「我」的诞生/data.json
	resources/meta-sr/weapon/智识/今日亦是和平的一日/data.json
	resources/meta-sr/weapon/智识/别让世界静下来/data.json
	resources/meta-sr/weapon/智识/天才们的休憩/data.json
	resources/meta-sr/weapon/智识/拂晓之前/data.json
	resources/meta-sr/weapon/智识/早餐的仪式感/data.json
	resources/meta-sr/weapon/智识/智库/data.json
	resources/meta-sr/weapon/智识/灵钥/data.json
	resources/meta-sr/weapon/智识/睿见/data.json
	resources/meta-sr/weapon/智识/银河铁道之夜/data.json
	resources/meta-sr/weapon/毁灭/乐圮/data.json
	resources/meta-sr/weapon/毁灭/俱殁/data.json
	resources/meta-sr/weapon/毁灭/在蓝天下/data.json
	resources/meta-sr/weapon/毁灭/天倾/data.json
	resources/meta-sr/weapon/毁灭/无可取代的东西/data.json
	resources/meta-sr/weapon/毁灭/无处可逃/data.json
	resources/meta-sr/weapon/毁灭/汪!散步时间!/data.json
	resources/meta-sr/weapon/毁灭/秘密誓心/data.json
	resources/meta-sr/weapon/毁灭/记一位星神的陨落/data.json
	resources/meta-sr/weapon/毁灭/鼹鼠党欢迎你/data.json
	resources/meta-sr/weapon/虚无/以世界之名/data.json
	resources/meta-sr/weapon/虚无/决心如汗珠般闪耀/data.json
	resources/meta-sr/weapon/虚无/匿影/data.json
	resources/meta-sr/weapon/虚无/后会有期/data.json
	resources/meta-sr/weapon/虚无/幽邃/data.json
	resources/meta-sr/weapon/虚无/延长记号/data.json
	resources/meta-sr/weapon/虚无/晚安与睡颜/data.json
	resources/meta-sr/weapon/虚无/渊环/data.json
	resources/meta-sr/weapon/虚无/猎物的视线/data.json
This commit is contained in:
Kokomi 2023-05-27 04:45:26 +08:00
commit ea2919d31f
201 changed files with 5412 additions and 2199 deletions

View File

@ -1,3 +1,9 @@
# 2.4.0 Dev
* 尚未完成不推荐切换至Dev
* 初步支持星铁面板数据获取与展示
* 面板属性计算暂未包含武器及圣遗物Buff面板数据暂不准确
# 2.3.8
* 面板服务增加由**Snap Hutao**提供的Enka转发代理可通过`#喵喵设置面板服务4`进行选择

View File

@ -14,6 +14,13 @@ let app = App.init({
})
app.reg({
profileList: {
name: '面板角色列表',
desc: '查看当前已获取面板数据的角色列表',
fn: ProfileList.render,
rule: /^#(星铁|原神)?(面板角色|角色面板|面板)(列表)?\s*(\d{9})?$/
},
profileDetail: {
name: '角色面板',
fn: ProfileDetail.detail,
@ -62,13 +69,6 @@ app.reg({
rule: /^#圣遗物列表\s*(\d{9})?$/
},
profileList: {
name: '面板角色列表',
desc: '查看当前已获取面板数据的角色列表',
fn: ProfileList.render,
rule: /^#(面板角色|角色面板|面板)(列表)?\s*(\d{9})?$/
},
profileStat: {
name: '面板练度统计',
fn: ProfileStat.stat,
@ -102,7 +102,7 @@ app.reg({
name: '面板更新',
describe: '【#角色】 获取游戏橱窗详情数据',
fn: ProfileList.refresh,
rule: /^#(全部面板更新|更新全部面板|获取游戏角色详情|更新面板|面板更新)\s*(\d{9})?$/
rule: /^#(星铁|原神)?(全部面板更新|更新全部面板|获取游戏角色详情|更新面板|面板更新)\s*(\d{9})?$/
},
uploadImg: {

View File

@ -86,7 +86,7 @@ const ProfileChange = {
let wRet = /^(?:等?级?([1-9][0-9])?级?)?\s*(?:([1-5一二三四五满])?精炼?([1-5一二三四五])?)?\s*(?:等?级?([1-9][0-9])?级?)?\s*(.*)$/.exec(txt)
if (wRet && wRet[5]) {
let weaponName = lodash.trim(wRet[5])
let weapon = Weapon.get(weaponName)
let weapon = Weapon.get(weaponName, ret.char.game)
if (weapon || weaponName === '武器' || Weapon.isWeaponSet(weaponName)) {
let affix = wRet[2] || wRet[3]
affix = { : 1, : 2, : 3, : 4, : 5, : 5 }[affix] || affix * 1
@ -195,14 +195,14 @@ const ProfileChange = {
elem: char.elem,
dataSource: 'change',
promote
}, false)
}, char.game, false)
// 设置武器
let wCfg = ds.weapon || {}
let wSource = getSource(wCfg).weapon || {}
let weapon = Weapon.get(wCfg?.weapon || wSource?.name || defWeapon[char.weaponType], char.weaponType)
let weapon = Weapon.get(wCfg?.weapon || wSource?.name || defWeapon[char.weaponType], char.game, char.weaponType)
if (!weapon || weapon.type !== char.weaponType) {
weapon = Weapon.get(defWeapon[char.weaponType])
weapon = Weapon.get(defWeapon[char.weaponType], char.game)
}
let wDs = {
name: weapon.name,

View File

@ -1,12 +1,14 @@
import lodash from 'lodash'
import { getTargetUid, getProfileRefresh } from './ProfileCommon.js'
import ProfileList from './ProfileList.js'
import { Cfg, Common, Format } from '#miao'
import { Cfg, Common, Data, Format } from '#miao'
import { MysApi, ProfileRank, ProfileArtis, Character, Weapon } from '#miao.models'
import ProfileChange from './ProfileChange.js'
import { profileArtis } from './ProfileArtis.js'
import { ProfileWeapon } from './ProfileWeapon.js'
let { diyCfg } = await Data.importCfg('profile')
// 查看当前角色
let ProfileDetail = {
async detail (e) {
@ -40,7 +42,7 @@ let ProfileDetail = {
msg = msg.replace(uidRet[0], '')
}
let name = msg.replace(/#|老婆|老公/g, '').trim()
let name = msg.replace(/#|老婆|老公|星铁|原神/g, '').trim()
msg = msg.replace('面版', '面板')
let dmgRet = /(?:伤害|武器)(\d?)$/.exec(name)
let dmgIdx = 0
@ -72,6 +74,9 @@ let ProfileDetail = {
if (!char) {
return false
}
if (/星铁/.test(msg) || char.isSr) {
e.isSr = true
}
let uid = e.uid || await getTargetUid(e)
if (!uid) {
@ -128,33 +133,39 @@ let ProfileDetail = {
let a = profile.attr
let base = profile.base
let attr = {}
lodash.forEach(['hp', 'def', 'atk', 'mastery'], (key) => {
let game = char.game
let isGs = game === 'gs'
lodash.forEach((isGs ? 'hp,def,atk,mastery' : 'hp,def,atk,speed').split(','), (key) => {
let fn = (n) => Format.comma(n, key === 'hp' ? 0 : 1)
attr[key] = fn(a[key])
attr[`${key}Base`] = fn(base[key])
attr[`${key}Plus`] = fn(a[key] - base[key])
})
lodash.forEach(['cpct', 'cdmg', 'recharge', 'dmg'], (key) => {
lodash.forEach((isGs ? 'cpct,cdmg,recharge,dmg' : 'cpct,cdmg,recharge,dmg,effPct,stance').split(','), (key) => {
let fn = Format.pct
let key2 = key
if (key === 'dmg' && a.phy > a.dmg) {
key2 = 'phy'
if (key === 'dmg') {
if (isGs) {
if (a.phy > a.dmg) {
key2 = 'phy'
}
}
}
attr[key] = fn(a[key2])
attr[`${key}Base`] = fn(base[key2])
attr[`${key}Plus`] = fn(a[key2] - base[key2])
})
let weapon = Weapon.get(profile.weapon.name)
let weapon = Weapon.get(profile.weapon.name, game)
let w = profile.weapon
let wCfg = {}
if (mode === 'weapon') {
wCfg = weapon.calcAttr(w.level, w.promote)
wCfg.info = weapon.getAffixInfo(weapon.affix)
wCfg.weapons = await ProfileWeapon.calc(profile)
}
let enemyLv = await selfUser.getCfg('char.enemyLv', 91)
let enemyLv = isGs ? (await selfUser.getCfg('char.enemyLv', 91)) : profile.level
let dmgCalc = await ProfileDetail.getProfileDmgCalc({ profile, enemyLv, mode, params })
let rank = false
@ -164,11 +175,14 @@ let ProfileDetail = {
}
let artisDetail = profile.getArtisMark()
let artisKeyTitle = ProfileArtis.getArtisKeyTitle()
let artisKeyTitle = ProfileArtis.getArtisKeyTitle(game)
let data = profile.getData('name,abbr,cons,level,talent,dataSource,updateTime,imgs,costumeSplash')
data.weapon = profile.getWeaponDetail()
let renderData = {
save_id: uid,
uid,
data: profile.getData('name,abbr,cons,level,weapon,talent,dataSource,updateTime,imgs,costumeSplash'),
game,
data,
attr,
elem: char.elem,
dmgCalc,
@ -192,6 +206,9 @@ let ProfileDetail = {
},
async getProfileDmgCalc ({ profile, enemyLv, mode, params }) {
if (profile.isSr && !diyCfg.srDmg) {
return false
}
let dmgMsg = []
let dmgData = []
let dmgCalc = await profile.calcDmg({
@ -201,8 +218,10 @@ let ProfileDetail = {
})
if (dmgCalc && dmgCalc.ret) {
lodash.forEach(dmgCalc.ret, (ds) => {
ds.dmg = Format.comma(ds.dmg, 0)
ds.avg = Format.comma(ds.avg, 0)
if (ds.type !== 'text') {
ds.dmg = Format.comma(ds.dmg, 0)
ds.avg = Format.comma(ds.avg, 0)
}
dmgData.push(ds)
})
lodash.forEach(dmgCalc.msg, (msg) => {

View File

@ -61,7 +61,7 @@ const ProfileList = {
isSelfUid = uids.join(',').split(',').includes(uid + '')
}
let rank = false
let servName = Player.getProfileServName(uid)
let hasNew = false
let newCount = 0
@ -75,10 +75,12 @@ const ProfileList = {
const cfg = await Data.importCfg('cfg')
// 获取面板数据
let player = Player.create(e)
let servName = Player.getProfileServName(uid, player.game)
if (!player.hasProfile) {
await player.refresh({ profile: true })
}
if (!player.hasProfile) {
console.log(player.game)
e.reply(`本地暂无uid${uid}的面板数据...`)
return true
}

View File

@ -55,14 +55,14 @@ export async function groupRank (e) {
e.uid = uid
return await ProfileDetail.render(e, char)
} else {
if (mode === 'dmg' && !ProfileDmg.dmgRulePath(char.name)) {
if (mode === 'dmg' && !ProfileDmg.dmgRulePath(char.name, char.game)) {
e.reply(`暂无排名:${char.name}暂不支持伤害计算,无法进行排名..`)
} else {
e.reply('暂无排名:请通过【#面板】查看角色面板以更新排名信息...')
}
}
} else if (type === 'list') {
if (mode === 'dmg' && char && !ProfileDmg.dmgRulePath(char.name)) {
if (mode === 'dmg' && char && !ProfileDmg.dmgRulePath(char.name, char.game)) {
e.reply(`暂无排名:${char.name}暂不支持伤害计算,无法进行排名..`)
} else {
let uids = []

View File

@ -1,7 +1,7 @@
import { ProfileData, Weapon } from '#miao.models'
export const ProfileWeapon = {
async calc (profile) {
async calc (profile, game = 'gs') {
let ret = []
await Weapon.forEach(async (w) => {
let weaponRet = w.getData('name,star,abbr,icon')
@ -13,7 +13,7 @@ export const ProfileWeapon = {
let tempProfile = new ProfileData({
...profile.getData('uid,id,level,cons,fetter,elem,promote,talent,artis'),
dataSource: 'change'
}, false)
}, game, false)
tempProfile.setWeapon({
name: w.name,

View File

@ -4,9 +4,10 @@ import { Common } from '#miao'
import { Character, MysApi, Player } from '#miao.models'
export async function AbyssTeam (e) {
let mys = await MysApi.init(e, 'cookie')
if (!mys || !mys.uid || !mys.isSelfCookie) {
return true
let mys = await MysApi.init(e, 'all')
if (!mys || !mys.uid) {
e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`)
return false
}
let player = Player.create(e)
await player.refreshMysDetail(2)

View File

@ -7,7 +7,7 @@
import fetch from 'node-fetch'
import { Data } from '#miao'
const host = 'http://miaoapi.cn/api/hutao'
const host = 'http://49.232.91.210/api/hutao'
function getApi (api) {
return `${host}?api=${api}`

View File

@ -96,7 +96,7 @@ let Cal = {
}
})
}
let miaoApi = 'http://miaoapi.cn/api/calendar'
let miaoApi = 'http://49.232.91.210/api/calendar'
try {
request2 = await fetch(miaoApi)
let data = await request2.json()

View File

@ -11,23 +11,39 @@ const elemAlias = {
cryo: '冰,至冬'
}
const elemAliasSR = {
fire: '火',
ice: '冰',
wind: '风',
elec: '雷',
phy: '物理',
quantum: '量子',
imaginary: '虚数'
}
// 元素属性映射, 名称=>elem
let elemMap = {}
let elemMapSR = {}
// 标准元素名
let elemTitleMap = {}
let elemTitleMapSR = elemAliasSR
lodash.forEach(elemAlias, (txt, key) => {
elemMap[key] = key
elemTitleMap[key] = txt[0]
Data.eachStr(txt, (t) => (elemMap[t] = key))
})
lodash.forEach(elemAliasSR, (txt, key) => {
elemMapSR[key] = key
elemMapSR[txt] = key
})
const Elem = {
// 根据名称获取元素key
elem (elem = '', defElem = '') {
elem (elem = '', defElem = '', game = 'gs') {
elem = elem.toLowerCase()
return elemMap[elem] || defElem
return (game === 'gs' ? elemMap : elemMapSR)[elem] || defElem
},
// 根据key获取元素名
@ -52,14 +68,19 @@ const Elem = {
return ''
},
eachElem (fn) {
lodash.forEach(elemTitleMap, (title, key) => {
eachElem (fn, game = 'gs') {
lodash.forEach(game === 'gs' ? elemTitleMap : elemTitleMapSR, (title, key) => {
fn(key, title)
})
},
isElem (elem = '') {
return !!elemMap[elem]
isElem (elem = '', game = 'gs') {
return !!(game === 'gs' ? elemMap : elemMapSR)[elem]
},
sameElem (key1, key2, game = 'gs') {
let map = (game === 'gs' ? elemMap : elemMapSR)
return map[key1] === map[key2]
}
}
export default Elem

View File

@ -4,11 +4,11 @@
* */
export const miaoApi = {
listApi: ({ url, uid, diyCfg }) => {
listApi: ({ url, uid, diyCfg, game = 'gs' }) => {
let qq = /\d{5,12}/.test(diyCfg.qq) ? diyCfg.qq : 'none'
let token = diyCfg.token
url = url || 'http://miaoapi.cn/'
return `${url}profile/data?uid=${uid}&qq=${qq}&token=${token}&version=2`
url = url || 'http://49.232.91.210/'
return `${url}profile/data?uid=${uid}&qq=${qq}&token=${token}&version=2&game=${game}`
}
}
@ -36,6 +36,13 @@ export const hutaoApi = {
}
}
export const homoApi = {
url: 'https://api.mihomo.me/sr_info',
listApi: ({ url, uid, diyCfg }) => {
return `${url}/${uid}`
}
}
export const requestInterval = 3
export const isSys = true

View File

@ -5,41 +5,54 @@ import Base from './Base.js'
import { Format } from '#miao'
import { ArtifactSet } from './index.js'
import { artiMap, attrMap, mainIdMap, attrIdMap } from '../resources/meta/artifact/index.js'
import { idMap as idMapSR, artiMap as artiMapSR, metaData as metaDataSR, abbr as abbrSR } from '../resources/meta-sr/artifact/index.js'
import lodash from 'lodash'
class Artifact extends Base {
static getAttrs
constructor (name) {
constructor (name, game = 'gs') {
super()
let cache = this._getCache(`arti:${name}`)
let cache = this._getCache(`arti:${game}:${name}`)
if (cache) {
return cache
}
let data = artiMap[name]
this.game = game
let data = (this.isGs ? artiMap : artiMapSR)[name]
if (!data) {
return false
}
this.name = name
this.id = data.id || ''
this.name = data.name
this.meta = data
return this._cache()
}
get artiSet () {
return ArtifactSet.get(this.set)
return ArtifactSet.get(this.set, this.game)
}
get setName () {
return this.set
}
get img () {
return `meta/artifact/imgs/${this.setName}/${this.idx}.webp`
get abbr () {
return (abbrSR && abbrSR[this.name]) || this.name
}
static get (name) {
if (artiMap[name]) {
return new Artifact(name)
get img () {
return this.isGs ? `meta/artifact/imgs/${this.setName}/${this.idx}.webp` : `meta-sr/artifact/${this.setName}/arti-${this.idx}.webp`
}
static get (name, game = 'gs') {
if (!name) {
return false
}
if (game === 'sr') {
name = idMapSR[name]?.name || name
}
if ((game === 'gs' ? artiMap : artiMapSR)[name]) {
return new Artifact(name, game)
}
return false
}
@ -96,6 +109,47 @@ class Artifact extends Base {
})
return ret
}
getStarById (id) {
return this.meta.ids[id] || ''
}
getAttrData (mainId, attrData, level = 1, star = 5, idx = 1) {
let mainKey = metaDataSR.mainIdx[idx][mainId]
let starCfg = metaDataSR.starData[star]
let mainCfg = starCfg.main[mainKey]
if (!mainId || !mainCfg) {
return false
}
let main = {
id: mainId,
key: mainKey,
value: mainCfg.base + mainCfg.step * level
}
let attrs = []
lodash.forEach(attrData, (ds) => {
let _ds = ds
if (lodash.isString(ds)) {
let [id, count, step] = ds.split(',')
ds = { id, count, step }
}
let attrCfg = starCfg.sub[ds.id]
if (!attrCfg) {
console.log('not found attr', ds, _ds)
return true
}
attrs.push({
...ds,
key: attrCfg?.key,
value: attrCfg?.base * ds.count + attrCfg.step * ds.step
})
})
return {
main,
attrs
}
}
}
export default Artifact

View File

@ -1,21 +1,30 @@
/*
* 圣遗物套装
* */
import lodash from 'lodash'
import Base from './Base.js'
import { abbr, artiMap, artiSetMap } from '../resources/meta/artifact/index.js'
import { abbr, artiMap, artiSetMap, calc as artisBuffs } from '../resources/meta/artifact/index.js'
import { artiMap as artiMapSR, artisBuffs as artisBuffsSR, artiSetMap as artiSetMapSR } from '../resources/meta-sr/artifact/index.js'
import { Artifact } from './index.js'
class ArtifactSet extends Base {
constructor (name) {
constructor (name, game = 'gs') {
super()
let cache = this._getCache(`arti-set:${name}`)
let cache = this._getCache(`arti-set:${game}:${name}`)
if (cache) {
return cache
}
let data = artiSetMap[name]
let data = (game === 'gs' ? artiSetMap : artiSetMapSR)[name]
if (!data) {
return false
if (artiSetMapSR[name]) {
data = artiSetMapSR[name]
game = 'sr'
} else {
return false
}
}
this.game = game
this.meta = data
return this._cache()
}
@ -33,24 +42,22 @@ class ArtifactSet extends Base {
if (artiMap[name]) {
return ArtifactSet.get(artiMap[name].set)
}
if (artiMapSR[name]) {
return ArtifactSet.get(artiMap[name].set, 'sr')
}
return false
}
static get (name) {
if (artiSetMap[name]) {
return new ArtifactSet(name)
return new ArtifactSet(name, 'gs')
}
if (artiSetMapSR[name]) {
return new ArtifactSet(name, 'sr')
}
return false
}
getArtiName (idx = 1) {
return this.sets[idx]
}
getArti (idx = 1) {
return Artifact.get(this.getArtiName(idx))
}
static getArtiNameBySet (set, idx = 1) {
let artiSet = ArtifactSet.get(set)
if (artiSet) {
@ -58,6 +65,22 @@ class ArtifactSet extends Base {
}
return ''
}
static getArtisSetBuff (name, num, game = 'gs') {
let artiBuffsMap = game === 'sr' ? artisBuffsSR : artisBuffs
let ret = (artiBuffsMap[name] && artiBuffsMap[name][num]) || artiBuffsMap[name + num]
if (!ret) return false
if (lodash.isPlainObject(ret)) return [ret]
return ret
}
getArtiName (idx = 1) {
return this.sets[idx]
}
getArti (idx = 1) {
return Artifact.get(this.getArtiName(idx))
}
}
export default ArtifactSet

View File

@ -8,8 +8,9 @@ import { Format, Data } from '#miao'
import ArtisMark from './profile/ArtisMark.js'
export default class AvatarArtis extends Base {
constructor (charid = 0) {
constructor (charid = 0, game = 'gs') {
super()
this.game = game
this.charid = charid
this.artis = {}
}
@ -27,12 +28,15 @@ export default class AvatarArtis extends Base {
}
get hasAttr () {
if (this.isSr) {
return true
}
return ArtisMark.hasAttr(this.artis)
}
static _eachArtisSet (sets, fn) {
static _eachArtisSet (sets, fn, game = 'gs') {
lodash.forEach(sets || [], (v, k) => {
let artisSet = ArtifactSet.get(k)
let artisSet = ArtifactSet.get(k, game)
if (artisSet) {
if (v >= 4) {
fn(artisSet, 2)
@ -42,44 +46,67 @@ export default class AvatarArtis extends Base {
})
}
static getArtisKeyTitle () {
return ArtisMark.getKeyTitleMap()
static getArtisKeyTitle (game = 'gs') {
return ArtisMark.getKeyTitleMap(game)
}
setArtisData (ds = {}, profile = false) {
// let force = !this.hasArtis || ArtisMark.hasAttr(ds) || !ArtisMark.hasAttr(this.artis)
if (!profile || (profile && ArtisMark.hasAttr(ds))) {
for (let idx = 1; idx <= 5; idx++) {
setArtisData (ds = {}, isProfile = false) {
if (!isProfile || (isProfile && ArtisMark.hasAttr(ds))) {
for (let idx = 1; idx <= (this.isGs ? 5 : 6); idx++) {
if (ds[idx] || ds[`arti${idx}`]) {
this.setArtis(idx, ds[idx] || ds[`arti${idx}`], profile)
this.setArtis(idx, ds[idx] || ds[`arti${idx}`], isProfile)
}
}
}
}
setArtis (idx = 1, ds = {}, profile = false) {
setArtis (idx = 1, ds = {}, isProfile = false) {
idx = idx.toString().replace('arti', '')
this.artis[idx] = this.artis[idx] || {}
let arti = this.artis[idx]
if (profile) {
arti.name = ds._name || ds.name || arti.name || ''
arti.set = ds._set || Artifact.getSetNameByArti(arti._name) || ds.set || ''
arti.level = ds._level || ds.level || 1
arti.star = ds._star || ds.star || 5
arti.main = ds.main
arti.attrs = ds.attrs
return true
}
arti.name = ds.name || arti.name || ''
arti.set = ds.set || Artifact.getSetNameByArti(arti.name) || ''
arti.level = ds.level || 1
arti.star = ds.star || 5
let artiObj
if (this.isSr) {
artiObj = Artifact.get(ds.id, this.game)
if (!artiObj) {
return false
}
arti.id = artiObj.id || ds.id || arti.id || ''
arti.name = artiObj.name || arti.name || ''
arti.set = artiObj.setName || arti.set || ''
arti.level = ds.level || arti.level || 1
arti.star = artiObj.getStarById(ds.id) || arti.star || 5
if (ds.mainId || ds.main) {
arti._name = ds._name || ds.name || arti._name || arti.name
arti._set = ds._set || Artifact.getSetNameByArti(arti._name) || arti._set || ''
arti._level = ds._level || ds.level || arti._level || arti.level
arti._star = ds._star || ds.star || arti._star || arti.star || 5
if (ds.mainId && ds.attrs) {
let attr = artiObj.getAttrData(ds.mainId, ds.attrs, arti.level, arti.star, idx)
if (attr) {
arti.mainId = ds.mainId
arti.main = attr.main || arti.main || {}
arti.attrs = attr.attrs || arti.attrs || {}
} else {
console.log('attr id error', ds.main, ds.mainId, idx, arti.level, arti.star)
}
}
return
} else {
if (isProfile) {
arti.name = ds._name || ds.name || arti.name || ''
arti.set = ds._set || Artifact.getSetNameByArti(arti._name) || ds.set || ''
arti.level = ds._level || ds.level || 1
arti.star = ds._star || ds.star || 5
arti.main = ds.main
arti.attrs = ds.attrs
} else {
arti.name = ds.name || arti.name || ''
arti.set = ds.set || Artifact.getSetNameByArti(arti.name) || ''
arti.level = ds.level || 1
arti.star = ds.star || 5
}
if (ds.mainId || ds.main) {
arti._name = ds._name || ds.name || arti._name || arti.name
arti._set = ds._set || Artifact.getSetNameByArti(arti._name) || arti._set || ''
arti._level = ds._level || ds.level || arti._level || arti.level
arti._star = ds._star || ds.star || arti._star || arti.star || 5
}
}
// 存在面板数据,更新面板数据
@ -120,14 +147,29 @@ export default class AvatarArtis extends Base {
toJSON () {
let ret = {}
for (let idx = 1; idx <= 5; idx++) {
for (let idx = 1; idx <= (this.isGs ? 5 : 6); idx++) {
let ds = this.artis[idx]
if (ds) {
let tmp = {
name: ds.name || '',
level: ds.level || 1,
star: ds.star || 5
}
if (!ds) {
continue
}
let tmp = {
level: ds.level || 1,
star: ds.star || 5
}
if (this.isSr) {
tmp.id = ds.id
tmp.mainId = ds.main?.id
tmp.attrs = []
lodash.forEach(ds.attrs, (as) => {
tmp.attrs.push([
as?.id || '',
as?.count || 1,
as?.step || 0
].join(','))
})
} else {
tmp.name = ds.name || ''
if ((ds.mainId && ds.attrIds) || (ds.main && ds.attrs)) {
if ((ds._name && ds._name !== ds.name) || (ds._level && ds._level !== ds.level) || (ds._star && ds._star !== ds.star)) {
tmp._name = ds._name || null
@ -147,8 +189,8 @@ export default class AvatarArtis extends Base {
}
}
}
ret[idx] = tmp
}
ret[idx] = tmp
}
return ret
}
@ -263,6 +305,6 @@ export default class AvatarArtis extends Base {
}
eachArtisSet (fn) {
AvatarArtis._eachArtisSet(this.sets, fn)
AvatarArtis._eachArtisSet(this.sets, fn, this.game)
}
}

View File

@ -2,14 +2,14 @@ import lodash from 'lodash'
import Base from './Base.js'
import moment from 'moment'
import { Character, AvatarArtis, ProfileData, Weapon } from './index.js'
import { Data } from '#miao'
import { Data, Format } from '#miao'
import AttrCalc from './profile/AttrCalc.js'
import Profile from './player/Profile.js'
const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',')
export default class AvatarData extends Base {
constructor (ds = {}, source) {
constructor (ds = {}, game = 'gs') {
super()
let char = Character.get({ id: ds.id, elem: ds.elem })
if (!char) {
@ -17,8 +17,9 @@ export default class AvatarData extends Base {
}
this.id = char.id
this.char = char
this.game = char.game || game
this.initArtis()
this.setAvatar(ds, source)
this.setAvatar(ds)
}
get hasTalent () {
@ -62,9 +63,10 @@ export default class AvatarData extends Base {
return {
enka: 'Enka.Network',
miao: '喵喵Api',
mgg: 'MiniGG-API',
mgg: 'MiniGG-Api',
hutao: 'Hutao-Enka',
mys: '米游社'
mys: '米游社',
homo: 'Mihomo'
}[this._source] || this._source
}
@ -82,8 +84,8 @@ export default class AvatarData extends Base {
return ''
}
static create (ds, source) {
let avatar = new AvatarData(ds)
static create (ds, game = 'gs') {
let avatar = new AvatarData(ds, game)
if (!avatar) {
return false
}
@ -91,7 +93,7 @@ export default class AvatarData extends Base {
}
initArtis () {
this.artis = new AvatarArtis(this.id)
this.artis = new AvatarArtis(this.id, this.game)
}
_get (key) {
@ -122,11 +124,12 @@ export default class AvatarData extends Base {
this._costume = ds.costume || this._costume || 0
this.elem = ds.elem || this.elem || this.char.elem || ''
this.promote = lodash.isUndefined(ds.promote) ? (this.promote || AttrCalc.calcPromote(this.level)) : (ds.promote || 0)
this._source = ds._source || ds.dataSource || this._source || ''
this.trees = ds.trees || this.trees || []
this._source = ds._source || this._source || ''
this._time = ds._time || this._time || now
this._update = ds._update || this._update || ds._time || now
this._talent = ds._talent || this._talent || ds._time || now
// 存在数据源时更新时间
if (source) {
this._update = now
@ -141,12 +144,13 @@ export default class AvatarData extends Base {
}
setWeapon (ds = {}) {
let w = Weapon.get(ds.name)
let w = Weapon.get(ds.name || ds.id, this.game)
if (!w) {
return false
}
this.weapon = {
name: ds.name,
id: ds.id || w.id,
name: ds.name || w.name,
level: ds.level || ds.lv || 1,
promote: lodash.isUndefined(ds.promote) ? AttrCalc.calcPromote(ds.level || ds.lv || 1) : (ds.promote || 0),
affix: ds.affix,
@ -157,6 +161,24 @@ export default class AvatarData extends Base {
}
}
getWeaponDetail () {
if (this.isGs) {
return this.weapon
}
let ret = {
...this.weapon
}
let wData = Weapon.get(ret.id, this.game)
ret.splash = wData.imgs.gacha
let attrs = wData.calcAttr(ret.level, ret.promote)
lodash.forEach(attrs, (val, key) => {
attrs[key] = Format.comma(val, 1)
})
ret.attrs = attrs
ret.desc = wData.getAffixDesc(ret.affix)
return ret
}
setTalent (ds = false, mode = 'original', updateTime = '') {
const now = this._now || (new Date()) * 1
if (ds) {
@ -180,7 +202,7 @@ export default class AvatarData extends Base {
if (!this.isProfile) {
return false
}
return ProfileData.create(this)
return ProfileData.create(this, this.game)
}
// 判断当前profileData是否具备有效圣遗物信息
@ -190,18 +212,28 @@ export default class AvatarData extends Base {
// toJSON 供保存使用
toJSON () {
let keys = this.isGs ?
'name,id,elem,level,promote,fetter,costume,cons,talent:originalTalent' :
'name,id,elem,level,promote,cons,talent:originalTalent,trees'
return {
...this.getData('name,id,elem,level,promote,fetter,costume,cons,talent:originalTalent'),
weapon: Data.getData(this.weapon, 'name,level,promote,affix'),
...this.getData(keys),
weapon: Data.getData(this.weapon, this.isGs ? 'name,level,promote,affix' : 'id,level,promote,affix'),
...this.getData('artis,_source,_time,_update,_talent')
}
}
getDetail (keys = '') {
let imgs = this.char.getImgs(this.costume)
return {
...(this.getData(keys || 'id,name,level,star,cons,fetter,elem,abbr,weapon,talent,artisSet') || {}),
...Data.getData(imgs, 'face,qFace,side,gacha')
if (this.isGs) {
return {
...(this.getData(keys || 'id,name,level,star,cons,fetter,elem,abbr,weapon,talent,artisSet') || {}),
...Data.getData(imgs, 'face,qFace,side,gacha')
}
} else {
return {
...(this.getData(keys || 'id,name,level,star,cons,elem,abbr,weapon,talent,artisSet,trees') || {}),
...Data.getData(imgs, 'face,qFace,gacha,preview')
}
}
}

View File

@ -12,6 +12,7 @@ let metaMap = {}
export default class Base {
constructor () {
this.game = 'gs'
let proxy = new Proxy(this, {
get (self, key, receiver) {
if (self._uuid && key === 'meta') {
@ -92,4 +93,12 @@ export default class Base {
delete cacheMap[id]
delete metaMap[id]
}
get isSr () {
return this.game === 'sr'
}
get isGs () {
return !this.isSr
}
}

View File

@ -15,15 +15,19 @@ import CharCfg from './character/CharCfg.js'
let { wifeMap, idSort, idMap } = CharId
let getMeta = function (name) {
return Data.readJSON(`resources/meta/character/${name}/data.json`, 'miao')
let getMeta = function (name, game = 'gs') {
if (game === 'gs') {
return Data.readJSON(`resources/meta/character/${name}/data.json`, 'miao')
} else {
return CharId.getSrMeta(name)
}
}
class Character extends Base {
// 默认获取的数据
_dataKey = 'id,name,abbr,title,star,elem,allegiance,weapon,birthday,astro,cncv,jpcv,ver,desc,talentCons'
constructor ({ id, name = '', elem = '' }) {
constructor ({ id, name = '', elem = '', game = 'gs' }) {
super()
// 检查缓存
let cacheObj = this._getCache(CharId.isTraveler(id) ? `character:${id}:${elem || 'anemo'}` : `character:${id}`)
@ -33,10 +37,13 @@ class Character extends Base {
// 设置数据
this._id = id
this.name = name
this.game = game
if (!this.isCustom) {
let meta = getMeta(name)
let meta = getMeta(name, game)
this.meta = meta
this.elem = Format.elem(elem || meta.elem, 'anemo')
if (this.isGs) {
this.elem = Format.elem(elem || meta.elem, 'anemo')
}
} else {
this.meta = {}
}
@ -45,7 +52,7 @@ class Character extends Base {
// 是否为官方角色
get isOfficial () {
return /[12]0\d{6}/.test(this._id)
return this.game === 'sr' || /[12]0\d{6}/.test(this._id)
}
// 是否为实装官方角色
@ -61,13 +68,21 @@ class Character extends Base {
// 是否为自定义角色
get isCustom () {
return !/[12]0\d{6}/.test(this._id)
return !this.isOfficial
}
get id () {
return this.isCustom ? this._id : this._id * 1
}
get isGs () {
return this.game === 'gs'
}
get isSr () {
return this.game === 'sr'
}
// 获取短名字
get sName () {
let name = this.name
@ -77,7 +92,7 @@ class Character extends Base {
// 是否是旅行者
get isTraveler () {
return CharId.isTraveler(this.id)
return this.isGs && CharId.isTraveler(this.id)
}
get weaponType () {
@ -86,6 +101,9 @@ class Character extends Base {
// 获取武器类型
get weaponTypeName () {
if (this.isSr) {
return this.weapon
}
const map = {
sword: '单手剑',
catalyst: '法器',
@ -99,6 +117,9 @@ class Character extends Base {
// 获取元素名称
get elemName () {
if (this.isSr) {
return this.elem
}
return Format.elemName(this.elem)
}
@ -114,6 +135,9 @@ class Character extends Base {
// 获取侧脸图像
get side () {
if (this.isSr) {
return this.getImgs().face
}
return this.getImgs().side
}
@ -134,6 +158,9 @@ class Character extends Base {
// 获取命座天赋等级
get talentCons () {
if (this.isSr) {
return this.meta?.talentCons || {}
}
if (this.isTraveler) {
return this.elem === 'dendro' ? { e: 3, q: 5 } : { e: 5, q: 3 }
}
@ -151,17 +178,20 @@ class Character extends Base {
}
// 基于角色名获取Character
static get (val) {
let id = CharId.getId(val, Character.gsCfg)
static get (val, game = 'gs') {
let id = CharId.getId(val, Character.gsCfg, game)
if (!id) {
return false
}
return new Character(id)
}
static forEach (fn, type = 'all') {
static forEach (fn, type = 'all', game = 'gs') {
lodash.forEach(idMap, (name, id) => {
let char = Character.get({ id, name })
if (char.game !== 'game') {
return true
}
if (type === 'release' && !char.isRelease) {
return true
}
@ -196,10 +226,26 @@ class Character extends Base {
return CharImg.getCardImg(this.name, se, def)
}
// 设置旅行者数据
// 设置天赋数据
getAvatarTalent (talent = {}, cons = 0, mode = 'original') {
return CharTalent.getAvatarTalent(this.id, talent, cons, mode, this.talentCons)
return CharTalent.getAvatarTalent(this, talent, cons, mode)
}
getTalentKey (id) {
if (this.talentId[id]) {
return this.talentId[id]
}
if (this.isSr) {
id = (id + '').replace(this.id, '')
return {
'001': 'a',
'002': 'e',
'003': 'q',
'004': 't',
'007': 'z'
}[id]
}
return false
}
// 检查老婆类型
@ -230,12 +276,16 @@ class Character extends Base {
this._imgs = {}
}
if (!this._imgs[cacheId]) {
this._imgs[cacheId] = CharImg.getImgs(this.name, costumeIdx, this.isTraveler ? this.elem : '', this.weaponType, this.talentCons)
if (this.isSr) {
this._imgs[cacheId] = CharImg.getImgsSr(this.name, this.talentCons)
} else {
this._imgs[cacheId] = CharImg.getImgs(this.name, costumeIdx, this.isTraveler ? this.elem : '', this.weaponType, this.talentCons)
}
}
let imgs = this._imgs[cacheId]
return {
...imgs,
qFace: Cfg.get('qFace') ? imgs.qFace : imgs.face
qFace: Cfg.get('qFace') ? (imgs.qFace || imgs.face) : imgs.face
}
}
@ -249,13 +299,14 @@ class Character extends Base {
if (this.isCustom) {
return {}
}
const path = 'resources/meta/character'
const path = this.isSr ? 'resources/meta-sr/character' : 'resources/meta/character'
const file = this.isSr ? 'data' : 'detail'
try {
if (this.isTraveler) {
this._detail = Data.readJSON(`${path}/旅行者/${this.elem}/detail.json`, 'miao')
this._detail = Data.readJSON(`${path}/旅行者/${this.elem}/${file}.json`, 'miao')
} else {
this._detail = Data.readJSON(`${path}/${this.name}/detail.json`, 'miao')
this._detail = Data.readJSON(`${path}/${this.name}/${file}.json`, 'miao')
}
} catch (e) {
console.log(e)
@ -277,6 +328,31 @@ class Character extends Base {
}
return this._artisRule
}
/**
* 获取等级属性
* @param level
* @param promote
* @returns {{}|boolean}
*/
getLvAttr (level, promote) {
let metaAttr = this.detail?.attr
if (!metaAttr) {
return false
}
if (this.isSr) {
let lvAttr = metaAttr[promote]
let ret = {}
lodash.forEach(lvAttr.attrs, (v, k) => {
ret[k] = v * 1
})
lodash.forEach(lvAttr.grow, (v, k) => {
ret[k] = ret[k] * 1 + v * (level - 1)
})
return ret
}
}
}
Character.CharId = CharId

View File

@ -13,19 +13,22 @@ import MysAvatar from './player/MysAvatar.js'
import Profile from './player/Profile.js'
Data.createDir('/data/UserData', 'root')
Data.createDir('/data/PlayerData/gs', 'root')
Data.createDir('/data/PlayerData/sr', 'root')
export default class Player extends Base {
constructor (uid) {
constructor (uid, game = 'gs') {
super()
uid = uid?._mys?.uid || uid?.uid || uid
if (!uid) {
return false
}
let cacheObj = this._getCache(`player:${uid}`)
let cacheObj = this._getCache(`player:${game}:${uid}`)
if (cacheObj) {
return cacheObj
}
this.uid = uid
this.game = game
this.reload()
return this._cache(100)
}
@ -41,25 +44,33 @@ export default class Player extends Base {
return ret
}
static create (e) {
get _file () {
if (this.isSr) {
return `/data/PlayerData/sr/${this.uid}.json`
} else {
return `/data/UserData/${this.uid}.json`
}
}
static create (e, game = 'gs') {
if (e?._mys?.uid || e.uid) {
// 传入为e
let player = new Player(e?._mys?.uid || e.uid)
let player = new Player(e?._mys?.uid || e.uid, (game === 'sr' || e.isSr) ? 'sr' : 'gs')
player.e = e
return player
} else {
return new Player(e)
return new Player(e, game)
}
}
// 获取面板更新服务名
static getProfileServName (uid) {
let Serv = Profile.getServ(uid)
static getProfileServName (uid, game = 'gs') {
let Serv = Profile.getServ(uid, game)
return Serv.name
}
static delByUid (uid) {
let player = Player.create(uid)
static delByUid (uid, game = 'gs') {
let player = Player.create(uid, game)
if (player) {
player.del()
}
@ -70,7 +81,7 @@ export default class Player extends Base {
*/
reload () {
let data
data = Data.readJSON(`/data/UserData/${this.uid}.json`, 'root')
data = Data.readJSON(this._file, 'root')
this.setBasicData(data)
if (data.chars) {
this.setAvatars(data.chars)
@ -104,13 +115,17 @@ export default class Player extends Base {
if (this._ck) {
ret._ck = this._ck
}
Data.writeJSON(`/data/UserData/${this.uid}.json`, ret, 'root')
if (this.isSr) {
Data.writeJSON(`/data/PlayerData/sr/${this.uid}.json`, ret, 'root')
} else {
Data.writeJSON(`/data/UserData/${this.uid}.json`, ret, 'root')
}
}
del () {
try {
Data.delFile(`/data/UserData/${this.uid}.json`, 'root')
ProfileRank.delUidInfo(this.uid)
Data.delFile(this._file, 'root')
ProfileRank.delUidInfo(this.uid, this.game)
this._delCache()
Bot.logger.mark(`【面板数据删除】${this.uid}本地文件数据已删除...`)
} catch (e) {
@ -154,12 +169,14 @@ export default class Player extends Base {
getAvatar (id, create = false) {
let char = Character.get(id)
let avatars = this._avatars
// 兼容处理旅行者的情况
if (char.isTraveler && !create) {
id = avatars['10000005'] ? 10000005 : 10000007
if (this.isGs) {
// 兼容处理旅行者的情况
if (char.isTraveler && !create) {
id = avatars['10000005'] ? 10000005 : 10000007
}
}
if (!avatars[id] && create) {
avatars[id] = AvatarData.create({ id })
avatars[id] = AvatarData.create({ id }, this.game)
}
return avatars[id] || false
}

View File

@ -10,8 +10,8 @@ import { attrMap } from '../resources/meta/artifact/index.js'
import CharArtis from './profile/CharArtis.js'
export default class ProfileArtis extends AvatarArtis {
constructor (charid = 0, elem = '') {
super(charid)
constructor (charid = 0, elem = '', game = 'gs') {
super(charid, game)
this.elem = elem
}
@ -67,15 +67,16 @@ export default class ProfileArtis extends AvatarArtis {
let artis = {}
let setCount = {}
let totalMark = 0
let totalCrit = 0
let totalVaild = 0
let self = this
this.forEach((arti, idx) => {
let mark = ArtisMark.getMark(charCfg, idx, arti.main, arti.attrs, this.elem)
let crit = ArtisMark.getCritMark(charCfg, idx, arti.main, arti.attrs, this.elem)
let vaild = ArtisMark.getValidMark(charCfg, idx, arti.main, arti.attrs, this.elem)
let mark = ArtisMark.getMark({
charCfg,
idx,
arti,
elem: this.elem,
game: self.game
})
totalMark += mark
totalCrit += crit
totalVaild += vaild
setCount[arti.set] = (setCount[arti.set] || 0) + 1
if (!withDetail) {
artis[idx] = {
@ -84,17 +85,18 @@ export default class ProfileArtis extends AvatarArtis {
markClass: ArtisMark.getMarkClass(mark)
}
} else {
let artifact = Artifact.get(arti.name)
let artifact = Artifact.get(arti.name, this.game)
artis[idx] = {
name: artifact.name,
abbr: artifact.abbr,
set: artifact.setName,
img: artifact.img,
level: arti.level,
_mark: mark,
mark: Format.comma(mark, 1),
markClass: ArtisMark.getMarkClass(mark),
main: ArtisMark.formatArti(arti.main, charCfg.attrs, true, this.elem || ''),
attrs: ArtisMark.formatArti(arti.attrs, charCfg.attrs)
main: ArtisMark.formatArti(arti.main, charCfg.attrs, true, this.game),
attrs: ArtisMark.formatArti(arti.attrs, charCfg.attrs, false, this.game)
}
}
})
@ -114,10 +116,10 @@ export default class ProfileArtis extends AvatarArtis {
let ret = {
mark: Format.comma(totalMark, 1),
_mark: totalMark,
crit: Format.comma(totalCrit, 1),
/* crit: Format.comma(totalCrit, 1),
_crit: totalCrit,
valid: Format.comma(totalVaild, 1),
_valid: totalVaild,
_valid: totalVaild, */
markClass: ArtisMark.getMarkClass(totalMark / 5),
artis,
sets,

View File

@ -1,17 +1,26 @@
import lodash from 'lodash'
import Base from './Base.js'
import { Format } from '#miao'
const baseAttr = 'atk,def,hp,mastery,recharge,cpct,cdmg,dmg,phy,heal,shield'.split(',')
let attrReg = new RegExp(`^(${baseAttr.join('|')})(Base|Plus|Pct|Inc)$`)
const baseAttr = {
gs: 'atk,def,hp,mastery,recharge,cpct,cdmg,dmg,phy,heal,shield'.split(','),
sr: 'atk,def,hp,speed,recharge,cpct,cdmg,dmg,heal,stance,effPct,effDmg'.split(',')
}
let attrReg = {
gs: new RegExp(`^(${baseAttr.gs.join('|')})(Base|Plus|Pct|Inc)$`),
sr: new RegExp(`^(${baseAttr.sr.join('|')})(Base|Plus|Pct|Inc)$`)
}
class ProfileAttr extends Base {
constructor (data = null) {
constructor (char, data = null) {
super()
this.init(data)
this.char = char
this.game = char.game
this.init(data, this.game)
}
static create (data = null) {
return new ProfileAttr(data)
static create (char, data = null) {
return new ProfileAttr(char, data)
}
init (data) {
@ -20,7 +29,7 @@ class ProfileAttr extends Base {
this._base = {}
let attr = this._attr
let base = this._base
lodash.forEach(baseAttr, (key) => {
lodash.forEach(baseAttr[this.game], (key) => {
attr[key] = {
base: 0,
plus: 0,
@ -28,6 +37,7 @@ class ProfileAttr extends Base {
}
base[key] = 0
})
if (data) {
this.setAttr(data, true)
}
@ -42,12 +52,12 @@ class ProfileAttr extends Base {
*/
_get (key) {
let attr = this._attr
if (baseAttr.includes(key)) {
if (baseAttr[this.game].includes(key)) {
let a = attr[key]
return a.base * (1 + a.pct / 100) + a.plus
}
let testRet = attrReg.exec(key)
let testRet = attrReg[this.game].exec(key)
if (testRet && testRet[1] && testRet[2]) {
let key = testRet[1]
let key2 = testRet[2].toLowerCase()
@ -59,13 +69,20 @@ class ProfileAttr extends Base {
* 添加或追加Attr数据
* @param key
* @param val
* @param base
* @param isBase
* @returns {boolean}
*/
addAttr (key, val, isBase = false) {
let attr = this._attr
let base = this._base
if (baseAttr.includes(key)) {
if (this.isSr && Format.isElem(key, this.game)) {
if (Format.sameElem(this.char.elem, key, this.game)) {
key = 'dmg'
}
}
if (baseAttr[this.game].includes(key)) {
attr[key].plus += val * 1
if (isBase) {
base[key] = (base[key] || 0) + val * 1
@ -73,7 +90,7 @@ class ProfileAttr extends Base {
return true
}
let testRet = attrReg.exec(key)
let testRet = attrReg[this.game].exec(key)
if (testRet && testRet[1] && testRet[2]) {
let key = testRet[1]
let key2 = testRet[2].toLowerCase()
@ -103,13 +120,19 @@ class ProfileAttr extends Base {
})
}
lodash.forEach(data, (val, key) => {
this.addAttr(key, val)
if (this.isSr && Format.isElem(key, this.game)) {
if (this.char.elem === Format.elem(key, '', this.game)) {
this.addAttr('dmg', val)
}
} else {
this.addAttr(key, val)
}
})
}
getAttr () {
let ret = {}
lodash.forEach(baseAttr, (key) => {
lodash.forEach(baseAttr[this.game], (key) => {
ret[key] = this[key]
if (['hp', 'atk', 'def'].includes(key)) {
ret[`${key}Base`] = this[`${key}Base`]

View File

@ -6,8 +6,8 @@ import AttrCalc from './profile/AttrCalc.js'
import CharImg from './character/CharImg.js'
export default class ProfileData extends AvatarData {
constructor (ds = {}, calc = true) {
super(ds)
constructor (ds = {}, game = 'gs', calc = true) {
super(ds, game)
if (calc) {
this.calcAttr()
}
@ -50,11 +50,11 @@ export default class ProfileData extends AvatarData {
}
get hasDmg () {
return this.hasData && !!ProfileDmg.dmgRulePath(this.name)
return this.hasData && !!ProfileDmg.dmgRulePath(this.name, this.game)
}
static create (ds) {
let profile = new ProfileData(ds)
static create (ds, game = 'gs') {
let profile = new ProfileData(ds, game)
if (!profile) {
return false
}
@ -62,7 +62,7 @@ export default class ProfileData extends AvatarData {
}
initArtis () {
this.artis = new ProfileArtis(this.id, this.elem)
this.artis = new ProfileArtis(this.id, this.elem, this.game)
}
setAttr (ds) {
@ -96,10 +96,10 @@ export default class ProfileData extends AvatarData {
// 计算当前profileData的伤害信息
async calcDmg ({ enemyLv = 91, mode = 'profile', dmgIdx = 0 }) {
if (!this.dmg) {
let ds = this.getData('id,level,attr,cons,artis:artis.sets')
let ds = this.getData('id,level,attr,cons,artis:artis.sets,trees')
ds.talent = lodash.mapValues(this.talent, 'level')
ds.weapon = Data.getData(this.weapon, 'name,affix')
this.dmg = new ProfileDmg(ds)
this.dmg = new ProfileDmg(ds, this.game)
}
return await this.dmg.calcData({ enemyLv, mode, dmgIdx })
}

View File

@ -2,33 +2,36 @@ import fs from 'fs'
import lodash from 'lodash'
import Base from './Base.js'
import { Character } from './index.js'
import { attrMap } from '../resources/meta/artifact/index.js'
import { attrMap as attrMapGS } from '../resources/meta/artifact/index.js'
import { attrMap as attrMapSR } from '../resources/meta-sr/artifact/index.js'
import DmgBuffs from './profile/DmgBuffs.js'
import DmgAttr from './profile/DmgAttr.js'
import DmgCalc from './profile/DmgCalc.js'
import { Common } from '#miao'
export default class ProfileDmg extends Base {
constructor (profile = {}) {
constructor (profile = {}, game = 'gs') {
super()
this.profile = profile
this.game = game
if (profile && profile.id) {
let { id } = profile
this.char = Character.get(id)
}
}
static dmgRulePath (name) {
static dmgRulePath (name, game = 'gs') {
const _path = process.cwd()
let path = `${_path}/plugins/miao-plugin/resources/meta/character/${name}/calc_user.js`
const meta = game === 'sr' ? 'meta-sr' : 'meta'
let path = `${_path}/plugins/miao-plugin/resources/${meta}/character/${name}/calc_user.js`
if (fs.existsSync(path)) {
return path
}
path = `${_path}/plugins/miao-plugin/resources/meta/character/${name}/calc_auto.js`
path = `${_path}/plugins/miao-plugin/resources/${meta}/character/${name}/calc_auto.js`
if (fs.existsSync(path) && Common.cfg('teamCalc')) {
return path
}
path = `${_path}/plugins/miao-plugin/resources/meta/character/${name}/calc.js`
path = `${_path}/plugins/miao-plugin/resources/${meta}/character/${name}/calc.js`
if (fs.existsSync(path)) {
return path
}
@ -42,41 +45,17 @@ export default class ProfileDmg extends Base {
let ret = {}
let talentData = profile.talent || {}
let detail = char.detail
lodash.forEach(['a', 'e', 'q'], (key) => {
let { isSr, isGs } = this
lodash.forEach((isSr ? 'a,e,q,t' : 'a,e,q').split(','), (key) => {
let level = lodash.isNumber(talentData[key]) ? talentData[key] : (talentData[key]?.level || 1)
let map = {}
if (detail.talentData) {
lodash.forEach(char.detail.talentData[key], (ds, key) => {
if (isGs && detail.talentData) {
lodash.forEach(detail.talentData[key], (ds, key) => {
map[key] = ds[level - 1]
})
} else {
lodash.forEach(char.detail.talent[key].tables, (tr) => {
let val = tr.values[level - 1]
// 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
if (isNaN(valArr[0])) {
map[name] = false
} else if (valArr.length === 1) {
map[name] = valArr[0]
} else {
map[name] = valArr
}
map[name + '2'] = valArr2
} else if (isSr && detail.talent) {
lodash.forEach(detail.talent[key].tables, (ds) => {
map[ds.name] = ds.values[level - 1]
})
}
ret[key] = map
@ -84,13 +63,25 @@ export default class ProfileDmg extends Base {
return ret
}
trees () {
let ret = {}
let reg = /\d{4}(\d{3})/
lodash.forEach(this.profile.trees, (t) => {
let regRet = reg.exec(t)
if (regRet && regRet[1]) {
ret[regRet[1]] = true
}
})
return ret
}
// 获取buff列表
getBuffs (buffs) {
return DmgBuffs.getBuffs(this.profile, buffs)
return DmgBuffs.getBuffs(this.profile, buffs, this.game)
}
async getCalcRule () {
const cfgPath = ProfileDmg.dmgRulePath(this.char?.name)
const cfgPath = ProfileDmg.dmgRulePath(this.char?.name, this.char?.game)
let cfg = {}
if (cfgPath) {
cfg = await import(`file://${cfgPath}`)
@ -101,7 +92,7 @@ export default class ProfileDmg extends Base {
defDmgIdx: cfg.defDmgIdx || -1, // 默认详情index
defDmgKey: cfg.defDmgKey || '',
mainAttr: cfg.mainAttr || 'atk,cpct,cdmg', // 伤害属性
enemyName: cfg.enemyName || '小宝' // 敌人名称
enemyName: cfg.enemyName || this.isGs ? '小宝' : '弱点敌人' // 敌人名称
}
}
return false
@ -112,6 +103,8 @@ export default class ProfileDmg extends Base {
return false
}
let { profile } = this
let { game } = this.char
let sp = this.detail?.sp
let charCalcData = await this.getCalcRule()
if (!charCalcData) {
@ -123,13 +116,15 @@ export default class ProfileDmg extends Base {
let meta = {
cons: profile.cons * 1,
talent
talent,
trees: this.trees()
}
let { id, weapon, attr } = profile
defParams = defParams || {}
let originalAttr = DmgAttr.getAttr({ id, weapon, attr, char: this.char })
let originalAttr = DmgAttr.getAttr({ id, weapon, attr, char: this.char, game, sp })
buffs = this.getBuffs(buffs)
@ -173,7 +168,7 @@ export default class ProfileDmg extends Base {
}
let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta, params))
let dmg = DmgCalc.getDmgFn({ ds, attr, level: profile.level, enemyLv, showDetail: detail.showDetail })
let dmg = DmgCalc.getDmgFn({ ds, attr, level: profile.level, enemyLv, showDetail: detail.showDetail, game })
let basicDmgRet
if (detail.dmg) {
@ -209,6 +204,8 @@ export default class ProfileDmg extends Base {
attr: []
}
let attrMap = game === 'gs' ? attrMapGS : attrMapSR
// 计算角色属性增减
mainAttr = mainAttr.split(',')
let params = lodash.merge({}, defParams, detail.params || {})
@ -228,10 +225,11 @@ export default class ProfileDmg extends Base {
params,
incAttr,
reduceAttr,
talent: detail.talent || ''
talent: detail.talent || '',
game
})
let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta, params))
let dmg = DmgCalc.getDmgFn({ ds, attr, level: profile.level, enemyLv })
let dmg = DmgCalc.getDmgFn({ ds, attr, level: profile.level, enemyLv, game })
if (detail.dmg) {
let dmgCalcRet = detail.dmg(ds, dmg)
rowData.push({

View File

@ -2,20 +2,21 @@ import Base from './Base.js'
import fetch from 'node-fetch'
export default class ProfileReq extends Base {
constructor (e) {
constructor (e, game = 'gs') {
super()
this.e = e
this.game = game
this.uid = e.uid
}
static create (e) {
static create (e, game = 'gs') {
if (!e || !e.uid) {
return false
}
if (e.uid * 1 < 100000005) {
return false
}
return new ProfileReq(e)
return new ProfileReq(e, game)
}
async setCd (seconds = 60) {
@ -67,10 +68,10 @@ export default class ProfileReq extends Base {
let self = this
this.serv = serv
let uid = this.uid
let reqParam = await serv.getReqParam(uid)
let reqParam = await serv.getReqParam(uid, self.game)
let cdTime = await this.inCd()
if (cdTime && !process.argv.includes('web-debug')) {
return this.err(`请求过快,请${cdTime}秒后重试..`)
// return this.err(`请求过快,请${cdTime}秒后重试..`)
}
await this.setCd(20)
// 若3秒后还未响应则返回提示
@ -107,7 +108,7 @@ export default class ProfileReq extends Base {
self._isReq = false
data = {}
}
data = await serv.response(data, this)
data = await serv.response(data, this, self.game)
// 设置CD
cdTime = serv.getCdTime(data)
if (cdTime) {

View File

@ -31,14 +31,15 @@ export default class ProfileServ extends Base {
}
// 请求当前面板服务
async getReqParam (uid) {
async getReqParam (uid, game = 'gs') {
let url = this.getCfg('url')
let profileApi = this.getCfg('listApi')
let cfg = this._cfg
let api = profileApi({
url,
uid: uid,
diyCfg: this.diyCfg
diyCfg: this.diyCfg,
game
})
let param = {}
@ -53,11 +54,11 @@ export default class ProfileServ extends Base {
}
}
async response (data, req) {
async response (data, req, game = 'gs') {
// 处理返回
let cfg = this._cfg
if (cfg.response) {
return await cfg.response.call(this, data, req)
return await cfg.response.call(this, data, req, game)
}
}

View File

@ -1,16 +1,22 @@
import Base from './Base.js'
import { Data } from '#miao'
import { weaponData, weaponAbbr, weaponAlias, weaponType, weaponSet } from '../resources/meta/weapon/index.js'
import { Data, Format } from '#miao'
import { weaponData, weaponAbbr, weaponAlias, weaponType, weaponSet, weaponBuffs } from '../resources/meta/weapon/index.js'
import {
weaponData as weaponDataSR,
weaponAlias as weaponAliasSR,
weaponBuffs as weaponBuffsSR
} from '../resources/meta-sr/weapon/index.js'
import lodash from 'lodash'
class Weapon extends Base {
constructor (name) {
constructor (name, game = 'gs') {
super(name)
let meta = weaponData[name]
let meta = game === 'gs' ? weaponData[name] : weaponDataSR[name]
if (!meta) {
return false
}
let cache = this._getCache(`weapon:${name}`)
let cache = this._getCache(`weapon:${game}:${name}`)
if (cache) {
return cache
}
@ -19,6 +25,7 @@ class Weapon extends Base {
this.meta = meta
this.type = meta.type
this.star = meta.star
this.game = game
return this._cache()
}
@ -31,14 +38,22 @@ class Weapon extends Base {
}
get img () {
return `meta/weapon/${this.type}/${this.name}/icon.webp`
return `${this.isGs ? 'meta' : 'meta-sr'}/weapon/${this.type}/${this.name}/icon.webp`
}
get imgs () {
return {
icon: `meta/weapon/${this.type}/${this.name}/icon.webp`,
icon2: `meta/weapon/${this.type}/${this.name}/awaken.webp`,
gacha: `meta/weapon/${this.type}/${this.name}/gacha.webp`
if (this.isGs) {
return {
icon: `meta/weapon/${this.type}/${this.name}/icon.webp`,
icon2: `meta/weapon/${this.type}/${this.name}/awaken.webp`,
gacha: `meta/weapon/${this.type}/${this.name}/gacha.webp`
}
} else {
return {
icon: `meta-sr/weapon/${this.type}/${this.name}/icon.webp`,
icon2: `meta-sr/weapon/${this.type}/${this.name}/icon-s.webp`,
gacha: `meta-sr/weapon/${this.type}/${this.name}/splash.webp`
}
}
}
@ -67,12 +82,13 @@ class Weapon extends Base {
return weaponSet.includes(name)
}
static get (name, type = '') {
static get (name, game = 'gs', type = '') {
name = lodash.trim(name)
if (weaponAlias[name]) {
return new Weapon(weaponAlias[name])
let alias = game === 'gs' ? weaponAlias : weaponAliasSR
if (alias[name]) {
return new Weapon(alias[name], game)
}
if (type) {
if (type && game === 'gs') {
let name2 = name + (weaponType[type] || type)
if (weaponAlias[name2]) {
return new Weapon(weaponAlias[name2])
@ -96,7 +112,7 @@ class Weapon extends Base {
if (this._detail) {
return this._detail
}
const path = 'resources/meta/weapon'
const path = this.isGs ? 'resources/meta/weapon' : 'resources/meta-sr/weapon'
try {
this._detail = Data.readJSON(`${path}/${this.type}/${this.name}/data.json`, 'miao')
} catch (e) {
@ -106,6 +122,22 @@ class Weapon extends Base {
}
calcAttr (level, promote = -1) {
let metaAttr = this.detail?.attr
if (!metaAttr) {
return false
}
if (this.isSr) {
let lvAttr = metaAttr[promote]
let ret = {}
lodash.forEach(lvAttr.attrs, (v, k) => {
ret[k] = v * 1
})
lodash.forEach(this.detail?.growAttr, (v, k) => {
ret[k] = ret[k] * 1 + v * (level - 1)
})
return ret
}
let lvLeft = 1
let lvRight = 20
let lvStep = [1, 20, 40, 50, 60, 70, 80, 90]
@ -140,22 +172,105 @@ class Weapon extends Base {
}
}
getAffixInfo (affix) {
let d = this.getDetail()
let ad = this.detail.affixData
let txt = ad.text
lodash.forEach(ad.datas, (ds, idx) => {
txt = txt.replace(`$[${idx}]`, ds[affix - 1])
})
return {
name: d.name,
star: d.star,
desc: d.desc,
imgs: this.imgs,
affix,
affixTitle: d.affixTitle,
affixDetail: txt
// 获取精炼描述
getAffixDesc (affix = 1) {
let skill = this.detail.skill
let { name, desc, tables } = skill
let reg = /\$(\d)\[[i|f1]\](\%?)/g
let ret
while ((ret = reg.exec(desc)) !== null) {
let idx = ret[1]
let pct = ret[2]
let value = tables?.[idx]?.[affix - 1]
if (pct === '%') {
value = Format.pct(value)
} else {
value = Format.comma(value)
}
desc = desc.replaceAll(ret[0], value)
}
return {
name: skill.name,
desc
}
}
getWeaponBuffs () {
let { isSr } = this
let wBuffs = (isSr ? weaponBuffsSR : weaponBuffs)
let buffs = wBuffs[this.id] || wBuffs[this.name]
if (!buffs) {
return false
}
if (lodash.isPlainObject(buffs) || lodash.isFunction(buffs)) {
buffs = [buffs]
}
return buffs
}
getWeaponAffixBuffs (affix, isStatic = true) {
let buffs = this.getWeaponBuffs()
let ret = []
let self = this
let { detail } = this
let tables = {}
lodash.forEach(detail?.skill?.tables || {}, (ds, idx) => {
tables[idx] = ds[affix - 1]
})
lodash.forEach(buffs, (ds) => {
if (lodash.isFunction(ds)) {
ds = ds(tables)
}
if (!!ds.isStatic !== !!isStatic) {
return true
}
// 静态属性
if (ds.isStatic) {
let tmp = {}
// 星铁武器格式
if (ds.idx && ds.key) {
if (!ds.idx || !ds.key) return true
if (!tables[ds.idx]) return true
tmp[ds.key] = tables[ds.idx]
}
if (ds.refine) {
lodash.forEach(ds.refine, (r, key) => {
tmp[key] = r[affix - 1] * (ds.buffCount || 1)
})
}
if (!lodash.isEmpty(tmp)) {
ret.push({
isStatic: true,
data: tmp
})
}
return true
}
// 自动拼接标题
if (!//.test(ds.title)) {
ds.title = `${self.name}${ds.title}`
}
ds.data = ds.data || {}
// refine
if (ds.idx && ds.key) {
if (!ds.idx || !ds.key) return true
if (!tables[ds.idx]) return true
ds.data[ds.key] = tables[ds.idx]
} else if (ds.refine) {
lodash.forEach(ds.refine, (r, key) => {
ds.data[key] = ({ refine }) => r[refine] * (ds.buffCount || 1)
})
}
ret.push(ds)
})
return ret
}
}

View File

@ -4,6 +4,8 @@
import lodash from 'lodash'
import { Data, Format } from '#miao'
import { charPosIdx } from './CharMeta.js'
import { aliasMap as aliasMapSR } from '../../resources/meta-sr/character/meta.js'
// 别名表
let aliasMap = {}
@ -16,8 +18,26 @@ let wifeMap = {}
// id排序
let idSort = {}
let gameMap = {}
let srData = Data.readJSON('/resources/meta-sr/character/data.json', 'miao')
async function init () {
let { sysCfg, diyCfg } = await Data.importCfg('character')
lodash.forEach(srData, (ds) => {
let { id, name } = ds
aliasMap[id] = id
aliasMap[name] = id
idMap[id] = name
gameMap[id] = 'sr'
})
// 添加别名
lodash.forEach(aliasMapSR, (v, k) => {
aliasMap[k] = aliasMap[v]
})
lodash.forEach([diyCfg.customCharacters, sysCfg.characters], (roleIds) => {
lodash.forEach(roleIds || {}, (aliases, id) => {
aliases = aliases || []
@ -31,6 +51,7 @@ async function init () {
})
aliasMap[id] = id
idMap[id] = aliases[0]
gameMap[id] = 'gs'
})
})
@ -66,15 +87,26 @@ lodash.forEach(charPosIdx, (chars, pos) => {
const CharId = {
aliasMap,
idMap,
gameMap,
abbrMap,
wifeMap,
idSort,
getId (ds = '', gsCfg = null) {
isGs (id) {
return gameMap[id] === 'gs'
},
isSr (id) {
return gameMap[id] === 'sr'
},
getId (ds = '', gsCfg = null, game = 'gs') {
if (!ds) {
return false
}
const ret = (id, elem = '') => {
return { id, elem, name: idMap[id] }
if (CharId.isSr(id)) {
return { id, name: idMap[id], game: 'sr' }
} else {
return { id, elem, name: idMap[id], game: 'gs' }
}
}
if (!lodash.isObject(ds)) {
let original = lodash.trim(ds || '')
@ -114,15 +146,19 @@ const CharId = {
return false
},
isTraveler (id) {
isTraveler (id, game = 'gs') {
if (id) {
return [10000007, 10000005, 20000000].includes(id * 1)
}
return false
},
getTravelerId (id) {
getTravelerId (id, game = 'gs') {
return id * 1 === 10000005 ? 10000005 : 10000007
},
getSrMeta (name) {
return srData?.[aliasMap[name]] || {}
}
}
export default CharId

View File

@ -118,6 +118,31 @@ const CharImg = {
imgs.e = talentCons.e === 3 ? imgs['cons3'] : imgs['cons5']
imgs.q = talentCons.q === 5 ? imgs['cons5'] : imgs['cons3']
return imgs
},
getImgsSr (name, talentCons) {
let fileType = 'webp'
const nPath = `/meta-sr/character/${name}/`
let imgs = {}
let add = (key, path, path2) => {
imgs[key] = `${nPath}${path}.${fileType}`
}
add('face', 'imgs/face')
add('splash', 'imgs/splash')
add('preview', 'imgs/preview')
for (let i = 1; i <= 3; i++) {
add(`tree${i}`, `imgs/tree-${i}`)
}
for (let key of ['a', 'e', 'q', 't', 'z']) {
add(key, `imgs/talent-${key}`)
}
for (let i = 1; i <= 6; i++) {
if (i !==3 && i !== 5) {
add(`cons${i}`, `imgs/cons-${i}`)
}
}
imgs.cons3 = imgs[talentCons[3]]
imgs.cons5 = imgs[talentCons[5]]
return imgs
}
}
export default CharImg

View File

@ -5,9 +5,14 @@ import lodash from 'lodash'
const CharTalent = {
// 处理获取天赋数据
getAvatarTalent (id, talent, cons, mode, consTalent = {}) {
getAvatarTalent (char, talent, cons, mode) {
let { id, talentCons, game, isGs } = char
let ret = {}
lodash.forEach(['a', 'e', 'q'], (key) => {
let addTalent = {
gs: { a: 0, e: 3, q: 3 },
sr: { a: 1, e: 2, q: 2, t: 2 }
}
lodash.forEach(addTalent[game], (addNum, key) => {
let ds = talent[key]
if (!ds) {
return false
@ -22,14 +27,14 @@ const CharTalent = {
if (mode !== 'level') {
// 基于original计算level
value = value || ds.original || ds.level_original || ds.level || ds.level_current
if (value > 10) {
if (value > 10 && isGs) {
mode = 'level'
} else {
original = value
if (key === 'a') {
if (key === 'a' && isGs) {
level = aPlus ? value + 1 : value
} else {
level = cons >= consTalent[key] ? (value + 3) : value
level = cons >= talentCons[key] ? (value + addNum) : value
}
}
}
@ -37,10 +42,10 @@ const CharTalent = {
// 基于level计算original
value = value || ds.level || ds.level_current || ds.original || ds.level_original
level = value
if (key === 'a') {
if (key === 'a' && isGs) {
original = aPlus ? value - 1 : value
} else {
original = cons >= consTalent[key] ? (value - 3) : value
original = cons >= talentCons[key] ? (value - addNum) : value
}
}
ret[key] = { level, original }

109
models/player/HomoApi.js Normal file
View File

@ -0,0 +1,109 @@
import lodash from 'lodash'
import { Data } from '#miao'
import { Character } from '#miao.models'
export default {
id: 'homo',
name: 'Mihomo',
cfgKey: 'homoApi',
// 处理请求参数
async request (api) {
let params = {
headers: { 'User-Agent': this.getCfg('userAgent') }
}
return { api, params }
},
// 处理服务返回
async response (data, req) {
if (!data.PlayerDetailInfo) {
return req.err('error', 60)
}
let ds = data.PlayerDetailInfo
let ac = ds.AssistAvatar
let avatars = {}
if (ac && !lodash.isEmpty(ac)) {
avatars[ac.AvatarID] = ac
}
lodash.forEach(ds.DisplayAvatarList, (ds) => {
avatars[ds.AvatarID] = ds
})
if (lodash.isEmpty(avatars)) {
return req.err('empty', 5 * 60)
}
data.avatars = avatars
return data
},
updatePlayer (player, data) {
try {
player.setBasicData(Data.getData(data, 'name:NickName,face:HeadIconID,level:Level,word:WorldLevel,sign:Signature'))
lodash.forEach(data.avatars, (ds, id) => {
let ret = HomoData.setAvatar(player, ds)
if (ret) {
player._update.push(ds.AvatarID)
}
})
} catch (e) {
console.log(e)
}
},
// 获取冷却时间
cdTime (data) {
return data.ttl || 60
}
}
const HomoData = {
setAvatar (player, data) {
let char = Character.get(data.AvatarID)
if (!char) {
return false
}
let avatar = player.getAvatar(char.id, true)
let setData = {
level: data.Level,
promote: data.Promotion,
cons: data.Rank || 0,
weapon: Data.getData(data.EquipmentID, 'id:ID,promote:Promotion,level:Level,affix:Rank'),
...HomoData.getTalent(data.BehaviorList, char),
artis: HomoData.getArtis(data.RelicList)
}
avatar.setAvatar(setData, 'homo')
return avatar
},
getTalent (ds, char) {
let talent = {}
let trees = []
lodash.forEach(ds, (d) => {
let key = char.getTalentKey(d.BehaviorID)
if (key || d.Level > 1) {
talent[key || d.BehaviorID] = d.Level
} else {
trees.push(d.BehaviorID)
}
})
return { talent, trees }
},
getArtis (artis) {
let ret = {}
lodash.forEach(artis, (ds) => {
let tmp = {
id: ds.ID,
level: ds.Level || 1,
mainId: ds.MainAffixID,
attrs: []
}
lodash.forEach(ds.RelicSubAffix, (s) => {
if (!s.SubAffixID) {
return true
}
tmp.attrs.push([s.SubAffixID, s.Cnt, s.Step || 0].join(','))
})
ret[ds.Type] = tmp
})
return ret
}
}

View File

@ -10,10 +10,13 @@ export default {
api = this.getCfg('api') || api
return { api }
},
async response (data, req) {
async response (data, req, game = 'gs') {
if (data.status !== 0) {
return req.err(data.msg || 'error', 60)
}
if (game === 'sr') {
return data.data
}
if (data.version === 2) {
data = data.data || {}
if (!data.avatars || data.avatars.length === 0) {
@ -22,32 +25,18 @@ export default {
data.version = 2
return data
} else {
data = data.data || {}
if (!data.showAvatarInfoList || data.showAvatarInfoList.length === 0) {
return req.err('empty', 5 * 60)
}
return data
return req.err('empty', 5 * 60)
}
},
updatePlayer (player, data) {
if (data.version === 2) {
player.setBasicData(data)
lodash.forEach(data.avatars, (avatar) => {
let ret = MiaoData.setAvatarNew(player, avatar)
if (ret) {
player._update.push(ret.id)
}
})
} else {
player.setBasicData(Data.getData(data, 'name:nickname,face:profilePicture.avatarId,card:nameCardID,level,word:worldLevel,sign:signature'))
lodash.forEach(data.showAvatarInfoList, (ds) => {
let ret = MiaoData.setAvatar(player, ds)
if (ret) {
player._update.push(ret.id)
}
})
}
player.setBasicData(data)
lodash.forEach(data.avatars, (avatar) => {
let ret = MiaoData.setAvatar(player, avatar)
if (ret) {
player._update.push(ret.id)
}
})
},
// 获取冷却时间

View File

@ -7,44 +7,26 @@ let MiaoData = {
setAvatar (player, ds) {
let char = Character.get(ds.id)
let avatar = player.getAvatar(ds.id, true)
let talentRet = MiaoData.getTalent(char.id, ds.skill)
avatar.setAvatar({
level: ds.level,
cons: ds.constellationNum || 0,
promote: ds.promoteLevel,
fetter: ds.fetterLevel,
costume: char.checkCostume(ds.costumeID) ? ds.costumeID : 0,
elem: talentRet.elem,
weapon: MiaoData.getWeapon(ds.weapon),
talent: talentRet.talent,
artis: MiaoData.getArtifact(ds.reliquary)
}, 'miao')
return avatar
},
setAvatarNew (player, ds) {
let char = Character.get(ds.id)
let avatar = player.getAvatar(ds.id, true)
let talentRet = MiaoData.getTalentNew(char.id, ds.talent)
avatar.setAvatar({
...ds,
elem: talentRet.elem,
talent: talentRet.talent
}, 'miao')
return avatar
},
getWeapon (weapon) {
return {
name: weapon.name,
level: weapon.level,
promote: weapon.promoteLevel,
affix: (weapon.affixLevel || 0) + 1
if (!char) {
return false
}
if (player.isSr) {
avatar.setAvatar({
...ds,
...MiaoData.getTalentSR(char, ds.talent)
}, 'miao')
} else {
let talentRet = MiaoData.getTalent(char, ds.talent)
avatar.setAvatar({
...ds,
elem: talentRet.elem,
talent: talentRet.talent
}, 'miao')
}
return avatar
},
getTalentNew (charid, data = {}) {
let char = Character.get(charid)
getTalent (char, data = {}) {
let { talentId = {}, talentElem = {} } = char.meta
let elem = ''
let idx = 0
@ -67,70 +49,18 @@ let MiaoData = {
}
},
getTalent (charid, data = {}) {
let char = Character.get(charid)
let { talentId = {}, talentElem = {} } = char.meta
let elem = ''
let idx = 0
let ret = {}
lodash.forEach(data, (ds) => {
let key
if (talentId[ds.id]) {
key = talentId[ds.id]
elem = elem || talentElem[ds.id]
ret[key] = {
level: ds.level
}
getTalentSR (char, data) {
let talent = {}
let trees = []
lodash.forEach(data, (lv, id) => {
let key = char.getTalentKey(id)
if (key || lv > 1) {
talent[key || id] = lv
} else {
key = ['a', 'e', 'q'][idx++]
ret[key] = ret[key] || {
level: ds.level
}
trees.push(id)
}
})
return {
talent: ret,
elem
}
},
getArtifact (data) {
let ret = {}
let get = function (d) {
if (!d) {
return []
}
let name = d.name
name = name.replace('FIGHT_PROP_', '')
if (!attrMap[name]) {
return []
}
let value = d.value
if (value && value < 1) {
value = value * 100
}
return { key: attrMap[name], value }
}
lodash.forEach(data, (ds) => {
let sub = ds.appendAffix || []
let idx = artisIdxMap[ds.type]
if (!idx) {
return
}
ret[idx] = {
name: ds.name,
level: ds.level,
star: ds.rank,
main: get(ds.mainAffix),
attrs: [
get(sub[0]),
get(sub[1]),
get(sub[2]),
get(sub[3])
]
}
})
return ret
return { talent, trees }
}
}
export default MiaoData

View File

@ -40,7 +40,6 @@ const MysAvatar = {
/**
* 更新米游社角色信息
* @param player
* @param mys
* @param force
* @returns {Promise<boolean>}
*/

View File

@ -6,6 +6,9 @@ import enkaApi from './EnkaApi.js'
import miaoApi from './MiaoApi.js'
import mggApi from './MggApi.js'
import hutaoApi from './HutaoApi.js'
import homoApi from './HomoApi.js'
import lodash from 'lodash'
let { diyCfg } = await Data.importCfg('profile')
@ -17,7 +20,8 @@ const Profile = {
miao: miaoApi,
mgg: mggApi,
enka: enkaApi,
hutao: hutaoApi
hutao: hutaoApi,
homo: homoApi
}[key])
}
return Profile.servs[key]
@ -26,9 +30,10 @@ const Profile = {
/**
* 根据UID分配请求服务器
* @param uid
* @param game
* @returns {ProfileServ}
*/
getServ (uid) {
getServ (uid, game = 'gs') {
let token = diyCfg?.miaoApi?.token
let qq = diyCfg?.miaoApi?.qq
let hasToken = !!(qq && token && token.length === 32 && !/^test/.test(token))
@ -40,6 +45,13 @@ const Profile = {
let servCfg = Cfg.get('profileServer', '0').toString() || '0'
servCfg = servCfg[servIdx] || servCfg[0] || '0'
if (game === 'sr') {
if ((servCfg === '0' || servCfg === '1') && hasToken) {
return Profile.serv('miao')
}
return Profile.serv('homo')
}
if ((servCfg === '0' || servCfg === '1') && hasToken) {
return Profile.serv('miao')
}
@ -68,13 +80,13 @@ const Profile = {
if (uid.toString().length !== 9 || !e) {
return false
}
let req = ProfileReq.create(e)
let req = ProfileReq.create(e, player.game)
if (!req) {
return false
}
let serv = Profile.getServ(uid)
let serv = Profile.getServ(uid, player.game)
try {
await req.requestProfile(player, serv)
await req.requestProfile(player, serv, player.game)
player._profile = new Date() * 1
player.save()
return player._update.length
@ -82,17 +94,21 @@ const Profile = {
if (!e._isReplyed) {
e.reply(`UID:${uid}更新面板失败,更新服务:${serv.name}`)
}
console.log(err)
return false
}
},
isProfile (avatar) {
if (avatar.isSr) {
return true
}
// 检查数据源
if (!avatar._source || !['enka', 'change', 'miao', 'mgg', 'hutao'].includes(avatar._source)) {
if (!avatar._source || !['enka', 'change', 'miao', 'mgg', 'hutao', 'homo'].includes(avatar._source)) {
return false
}
// 检查武器及天赋
if (!avatar.weapon || !avatar.talent) {
if (!avatar.weapon || lodash.isUndefined(avatar.weapon.promote) || !avatar.talent) {
return false
}
// 检查圣遗物词条是否完备

View File

@ -1,47 +1,40 @@
import lodash from 'lodash'
import { Format } from '#miao'
import { attrNameMap, mainAttr, subAttr, attrMap, basicNum, attrPct } from '../../resources/meta/artifact/index.js'
import { attrNameMap, mainAttr, subAttr, attrMap } from '../../resources/meta/artifact/index.js'
import {
attrMap as attrMapSR
} from '../../resources/meta-sr/artifact/meta.js'
let ArtisMark = {
// 根据Key获取标题
getKeyByTitle (title, dmg = false) {
getKeyByTitle (title, game = 'gs') {
if (/元素伤害加成/.test(title) || Format.isElem(title)) {
let elem = Format.matchElem(title)
return dmg ? 'dmg' : elem
return elem
} else if (title === '物理伤害加成') {
return 'phy'
}
return attrNameMap[title]
return (game === 'gs' ? attrNameMap : attrMap)[title]
},
// 根据标题获取Key
getTitleByKey (key) {
// 检查是否是伤害字段
let dmg = Format.elemName(key, '')
if (dmg) {
return `${dmg}伤加成`
}
return attrMap[key].title
},
getKeyTitleMap () {
getKeyTitleMap (game = 'gs') {
let ret = {}
lodash.forEach(attrMap, (ds, key) => {
lodash.forEach(game === 'gs' ? attrMap : attrMapSR, (ds, key) => {
ret[key] = ds.title
})
Format.eachElem((key, name) => {
ret[key] = `${name}伤加成`
})
}, game)
return ret
},
formatAttr (ds) {
formatAttr (ds, game = 'gs') {
if (!ds) {
return {}
}
if (lodash.isArray(ds) && ds[0] && ds[1]) {
return {
key: ArtisMark.getKeyByTitle(ds[0]),
key: ArtisMark.getKeyByTitle(ds[0], game),
value: ds[1]
}
}
@ -49,7 +42,7 @@ let ArtisMark = {
return {}
}
return {
key: ds.key || ArtisMark.getKeyByTitle(ds.title || ds.name || ds.key || ds.id || ''),
key: ds.key || ArtisMark.getKeyByTitle(ds.title || ds.name || ds.key || ds.id || '', game),
value: ds.value || ''
}
},
@ -57,76 +50,41 @@ let ArtisMark = {
/**
* 格式化圣遗物词条
* @param ds
* @param markCfg
* @param charAttrCfg
* @param isMain
* @param game
* @returns {{title: *, value: string}|*[]}
*/
formatArti (ds, charAttrCfg = false, isMain = false, elem = '') {
formatArti (ds, charAttrCfg = false, isMain = false, game = 'gs') {
// 若为attr数组
if (ds[0] && (ds[0].title || ds[0].key)) {
let ret = []
let totalUpNum = 0
let ltArr = []
let isIdAttr = false
lodash.forEach(ds, (d) => {
isIdAttr = !d.isCalcNum
let arti = ArtisMark.formatArti(d, charAttrCfg)
let arti = ArtisMark.formatArti(d, charAttrCfg, isMain, game)
ret.push(arti)
if (isIdAttr) {
return true
}
totalUpNum += arti.upNum
if (arti.hasLt) {
ltArr.push(arti)
}
delete arti.hasLt
delete arti.hasGt
})
if (!isIdAttr) {
ltArr = lodash.sortBy(ltArr, 'upNum').reverse()
for (let arti of ltArr) {
if (totalUpNum > 9) {
arti.upNum = arti.upNum - 1
totalUpNum--
} else {
break
}
}
}
return ret
}
let key = ds.key
let title = ds.title || ds[0]
if (!key) {
key = ArtisMark.getKeyByTitle(title)
} else if (!title) {
title = ArtisMark.getTitleByKey(key)
key = ArtisMark.getKeyByTitle(title, game)
}
let isDmg = Format.isElem(key)
let val = ds.value || ds[1]
let value = val
let num = ds.value || ds[1]
if (!key || key === 'undefined') {
return {}
}
let arrCfg = attrMap[isDmg ? 'dmg' : key]
val = Format[arrCfg.format](val, 1)
let arrCfg = (game === 'gs' ? attrMap : attrMapSR)[isDmg ? 'dmg' : key]
val = Format[arrCfg?.format || 'comma'](val, 1)
let ret = {
key,
value: val,
upNum: ds.upNum || 0,
eff: ds.eff || 0
}
if (!isMain && !ret.upNum) {
let incRet = ArtisMark.getIncNum(key, value)
ret.upNum = incRet.num
ret.eff = incRet.eff
ret.hasGt = incRet.hasGt
ret.hasLt = incRet.hasLt
ret.isCalcNum = true
}
if (charAttrCfg) {
let mark = charAttrCfg[key]?.mark * num || 0
@ -141,27 +99,6 @@ let ArtisMark = {
return ret
},
// 获取升级次数
getIncNum (key, value) {
let cfg = attrMap[key]
if (!value || !cfg || !cfg.value || !cfg.valueMin) {
return { num: 0 }
}
let maxNum = Math.min(5, Math.floor((value / cfg.valueMin).toFixed(1) * 1))
let minNum = Math.max(1, Math.ceil((value / cfg.value).toFixed(1) * 1))
// 相等时直接返回
if (maxNum === minNum) {
return { num: minNum, eff: value / cfg.value }
}
let avg = Math.round(value / (cfg.value + cfg.valueMin) * 2)
return {
num: avg,
eff: value / cfg.value,
hasGt: maxNum > avg,
hasLt: minNum < avg
}
},
// 获取评分档位
getMarkClass (mark) {
let pct = mark
@ -174,22 +111,27 @@ let ArtisMark = {
},
// 获取位置分数
getMark (charCfg, posIdx, mainAttr, subAttr, elem = '') {
getMark ({ charCfg, idx, arti, elem = '', game = 'gs' }) {
if (game === 'sr') {
return 0
}
let ret = 0
let mainAttr = arti.main
let subAttr = arti.attrs
let { attrs, posMaxMark } = charCfg
let key = mainAttr?.key
if (!key) {
return 0
}
let fixPct = 1
posIdx = posIdx * 1
if (posIdx >= 3) {
idx = idx * 1
if (idx >= 3) {
let mainKey = key
if (key !== 'recharge') {
if (posIdx === 4 && Format.isElem(key) && key === elem) {
if (idx === 4 && Format.isElem(key) && key === elem) {
mainKey = 'dmg'
}
fixPct = Math.max(0, Math.min(1, (attrs[mainKey]?.weight || 0) / (posMaxMark['m' + posIdx])))
fixPct = Math.max(0, Math.min(1, (attrs[mainKey]?.weight || 0) / (posMaxMark['m' + idx])))
}
ret += (attrs[mainKey]?.mark || 0) * (mainAttr.value || 0) / 4
}
@ -197,61 +139,7 @@ let ArtisMark = {
lodash.forEach(subAttr, (ds) => {
ret += (attrs[ds.key]?.mark || 0) * (ds.value || 0)
})
return ret * (1 + fixPct) / 2 / posMaxMark[posIdx] * 66
},
getCritMark (charCfg, posIdx, mainAttr, subAttr, elem = '') {
let ret = 0
let { attrs, posMaxMark } = charCfg
let key = mainAttr?.key
if (!key) {
return 0
}
let fixPct = 1
posIdx = posIdx * 1
if (posIdx >= 4) {
let mainKey = key
if (posIdx === 4 && Format.isElem(key) && key === elem) {
mainKey = 'dmg'
}
fixPct = Math.max(0, Math.min(1, (attrs[mainKey]?.weight || 0) / (posMaxMark['m' + posIdx])))
}
if (key === 'cpct' || key === 'cdmg') {
ret += 9.41
}
lodash.forEach(subAttr, (ds) => {
if (ds.key === 'cpct' || ds.key === 'cdmg') {
let temp_s = (attrs[ds.key]?.mark || 0) * (ds.value || 0) / 85
ret += temp_s
}
})
return ret
},
getValidMark (charCfg, posIdx, mainAttr, subAttr, elem = '') {
let ret = 0
let { attrs, posMaxMark } = charCfg
let key = mainAttr?.key
if (!key) {
return 0
}
let fixPct = 1
posIdx = posIdx * 1
if (posIdx >= 4) {
let mainKey = key
if (posIdx === 4 && Format.isElem(key) && key === elem) {
mainKey = 'dmg'
}
fixPct = Math.max(0, Math.min(1, (attrs[mainKey]?.weight || 0) / (posMaxMark['m' + posIdx])))
}
lodash.forEach(subAttr, (ds) => {
let temp_s = (attrs[ds.key]?.mark || 0) * (ds.value || 0) / 85
ret += temp_s
})
return ret
return ret * (1 + fixPct) / 2 / posMaxMark[idx] * 66
},
// 获取位置最高分
@ -300,7 +188,8 @@ let ArtisMark = {
for (let idx = 1; idx <= 5; idx++) {
let ds = artis[idx]
if (ds) {
if (!ds.name || !ds.main || !ds.attrs || !ds?.main?.key) {
// 不再支持非id格式的面板
if (!ds.attrs || !ds.mainId) {
return false
}
}

View File

@ -3,9 +3,8 @@
* @type {{}}
*/
import { Weapon, ProfileAttr } from '../index.js'
import { Weapon, ProfileAttr, ArtifactSet } from '../index.js'
import { Format } from '#miao'
import { calc as artisBuffs } from '../../resources/meta/artifact/index.js'
import { weaponBuffs } from '../../resources/meta/weapon/index.js'
import lodash from 'lodash'
@ -13,6 +12,15 @@ class AttrCalc {
constructor (profile) {
this.profile = profile
this.char = profile.char
this.game = this.char.game
}
get isGs () {
return this.game === 'gs'
}
get isSr () {
return this.game === 'sr'
}
/**
@ -24,6 +32,7 @@ class AttrCalc {
return new AttrCalc(profile)
}
// 只有原神才需要
static calcPromote (lv) {
if (lv === 20) {
return 1
@ -47,14 +56,17 @@ class AttrCalc {
* @returns {{}}
*/
calc () {
this.attr = ProfileAttr.create({})
this.addAttr('recharge', 100, true)
this.addAttr('cpct', 5, true)
this.addAttr('cdmg', 50, true)
this.attr = ProfileAttr.create(this.char, {})
if (this.isGs) {
this.addAttr('recharge', 100, true)
this.addAttr('cpct', 5, true)
this.addAttr('cdmg', 50, true)
}
this.setCharAttr()
this.setWeaponAttr()
this.setArtisAttr()
return this.attr.getAttr()
}
getBase () {
@ -71,8 +83,31 @@ class AttrCalc {
* @param affix
*/
setCharAttr (affix = '') {
let { char, level, promote } = this.profile
let { char, level, promote, trees } = this.profile
let metaAttr = char.detail?.attr || {}
let self = this
if (this.isSr) {
// 星铁面板属性
let attr = char.getLvAttr(level, promote)
lodash.forEach(attr, (v, k) => {
k = k + (['hp', 'atk', 'def'].includes(k) ? 'Base' : '')
self.addAttr(k, v, true)
})
let tree = char.detail?.tree || {}
lodash.forEach(trees || [], (tid) => {
let tCfg = tree[tid]
if (tCfg) {
let key = tCfg.key
if (['atk', 'hp', 'def'].includes(key)) {
key = key + 'Pct'
}
self.addAttr(key, tCfg.value)
}
})
return
}
let { keys = {}, details = {} } = metaAttr
let lvLeft = 0
let lvRight = 0
@ -123,9 +158,30 @@ class AttrCalc {
*/
setWeaponAttr () {
let wData = this.profile?.weapon || {}
let weapon = Weapon.get(wData?.name)
let weapon = Weapon.get(wData?.name || wData?.id, this.game)
let wCalcRet = weapon.calcAttr(wData.level, wData.promote)
let self = this
if (this.isSr) {
// 星铁面板属性
lodash.forEach(wCalcRet, (v, k) => {
k = k + (['hp', 'atk', 'def'].includes(k) ? 'Base' : '')
self.addAttr(k, v, true)
})
// 检查武器类型
if (weapon.type === this.char.weapon) {
// todo sr&gs 统一
let wBuffs = weapon.getWeaponAffixBuffs(wData.affix, true)
lodash.forEach(wBuffs, (buff) => {
lodash.forEach(buff.data || [], (v, k) => {
self.addAttr(k, v)
})
})
}
return
}
// 原神属性
if (wCalcRet) {
this.addAttr('atkBase', wCalcRet.atkBase)
this.addAttr(wCalcRet.attr?.key, wCalcRet.attr?.value)
@ -157,20 +213,24 @@ class AttrCalc {
artis.forEach((arti) => {
this.calcArtisAttr(arti.main, this.char)
lodash.forEach(arti.attrs, (ds) => {
this.calcArtisAttr(ds)
this.calcArtisAttr(ds, this.char)
})
})
// 计算圣遗物静态加成
artis.eachArtisSet((set, num) => {
let buff = artisBuffs[set.name] && artisBuffs[set.name][num]
if (!buff || !buff.isStatic) {
return true
}
if (buff.elem && !this.char.isElem(buff.elem)) {
return true
}
lodash.forEach(buff.data, (val, key) => {
this.addAttr(key, val)
let buffs = ArtifactSet.getArtisSetBuff(set.name, num, this.game)
if (!buffs) return true
lodash.forEach(buffs, (buff) => {
if (!buff.isStatic) {
return true
}
if (buff.elem && !this.char.isElem(buff.elem)) {
return true
}
lodash.forEach(buff.data, (val, key) => {
this.addAttr(key, val)
})
})
})
}
@ -178,6 +238,8 @@ class AttrCalc {
/**
* 计算单条圣遗物词缀
* @param ds
* @param char
* @param autoPct
* @returns {boolean}
*/
calcArtisAttr (ds, char) {

View File

@ -0,0 +1,32 @@
/**
* 旧面板数据迁移
* 去除旧格式控制逻辑复杂度
*/
import fs from 'node:fs'
import lodash from 'lodash'
import { Data } from '#miao'
const DataTrans = {
trans () {
const srcPath = './data/UserData'
let uids = fs.readdirSync(srcPath)
uids = uids.filter((uid) => /\.json/i.test(uid))
lodash.forEach(uids, (uid) => {
let data = Data.readJSON(`/data/UserData/${uid}`)
DataTrans.doTrans(data)
})
},
doTrans (data) {
lodash.forEach(data.avatars, (ds, id) => {
data.avatars[id] = DataTrans.getAvatar(ds)
})
},
getAvatar (data) {
let artisSet = {}
lodash.forEach(data.artis, (ds, idx) => {
})
}
}
export default DataTrans

View File

@ -1,19 +1,20 @@
/*
* 伤害计算 - 属性计算
* */
import { attrMap } from '../../resources/meta/artifact/index.js'
import { attrMap as attrMapGS } from '../../resources/meta/artifact/index.js'
import { attrMap as attrMapSR } from '../../resources/meta-sr/artifact/index.js'
import lodash from 'lodash'
import DmgMastery from './DmgMastery.js'
import { Format } from '#miao'
let DmgAttr = {
// 计算并返回指定属性值
getAttrValue (ds) {
getAttrValue (ds = {}) {
return (ds.base || 0) + (ds.plus || 0) + ((ds.base || 0) * (ds.pct || 0) / 100)
},
// 获取profile对应attr属性值
getAttr ({ id, attr, weapon, char }) {
getAttr ({ id, attr, weapon, char, game = 'gs' }) {
let ret = {}
// 基础属性
@ -25,7 +26,7 @@ let DmgAttr = {
}
})
lodash.forEach('mastery,recharge,cpct,cdmg,heal,dmg,phy'.split(','), (key) => {
lodash.forEach((game === 'gs' ? 'mastery,recharge,cpct,cdmg,heal,dmg,phy' : 'speed,recharge,cpct,cdmg,heal,dmg').split(','), (key) => {
ret[key] = {
base: attr[key] * 1 || 0, // 基础值
plus: 0, // 加成值
@ -35,7 +36,7 @@ let DmgAttr = {
})
// 技能属性记录
lodash.forEach('a,a2,a3,e,q'.split(','), (key) => {
lodash.forEach((game === 'gs' ? 'a,a2,a3,e,q' : 'a,a2,a3,e,q,t').split(','), (key) => {
ret[key] = {
pct: 0, // 倍率加成
multi: 0, // 独立倍率乘区加成宵宫E等
@ -67,21 +68,23 @@ let DmgAttr = {
ret.element = Format.elemName(char.elem) // 元素类型
ret.refine = ((weapon.affix || ret.refine || 1) * 1 - 1) || 0 // 武器精炼
ret.multi = 0 // 倍率独立乘区
ret.vaporize = 0 // 蒸发
ret.melt = 0 // 融化
ret.burning = 0 // 燃烧
ret.superConduct = 0 // 超导
ret.swirl = 0 // 扩散
ret.electroCharged = 0 // 感电
ret.shatter = 0 // 碎冰
ret.overloaded = 0 // 超载
ret.bloom = 0 // 绽放
ret.burgeon = 0 // 烈绽放
ret.hyperBloom = 0 // 超绽放
ret.aggravate = 0 // 超激化
ret.spread = 0 // 蔓激化
ret.kx = 0 // 敌人抗性降低
ret.fykx = 0 // 敌人反应抗性降低
if (game === 'gs') {
ret.vaporize = 0 // 蒸发
ret.melt = 0 // 融化
ret.burning = 0 // 燃烧
ret.superConduct = 0 // 超导
ret.swirl = 0 // 扩散
ret.electroCharged = 0 // 感电
ret.shatter = 0 // 碎冰
ret.overloaded = 0 // 超载
ret.bloom = 0 // 绽放
ret.burgeon = 0 // 烈绽放
ret.hyperBloom = 0 // 超绽放
ret.aggravate = 0 // 超激化
ret.spread = 0 // 蔓激化
ret.fykx = 0 // 敌人反应抗性降低
}
return ret
},
@ -101,10 +104,12 @@ let DmgAttr = {
},
// 计算属性
calcAttr ({ originalAttr, buffs, meta, params = {}, incAttr = '', reduceAttr = '', talent = '' }) {
calcAttr ({ originalAttr, buffs, meta, params = {}, incAttr = '', reduceAttr = '', talent = '', game = 'gs' }) {
let attr = lodash.merge({}, originalAttr)
let msg = []
let attrMap = game === 'gs' ? attrMapGS : attrMapSR
if (incAttr && attrMap[incAttr]) {
let aCfg = attrMap[incAttr]
attr[incAttr][aCfg.calc] += aCfg.value
@ -144,6 +149,16 @@ let DmgAttr = {
return
}
}
if (!lodash.isUndefined(buff.maxCons)) {
if (ds.cons * 1 > buff.maxCons * 1) {
return
}
}
if (buff.tree) {
if (!ds.trees[`10${buff.tree}`]) {
return
}
}
let title = buff.title
@ -163,12 +178,12 @@ let DmgAttr = {
title = title.replace(`[${key}]`, Format.comma(val, 1))
// 技能提高
let tRet = /^(a|a2|a3|e|q)(Def|Ignore|Dmg|Plus|Pct|Cpct|Cdmg|Multi)$/.exec(key)
let tRet = /^(a|a2|a3|e|q|t)(Def|Ignore|Dmg|Plus|Pct|Cpct|Cdmg|Multi)$/.exec(key)
if (tRet) {
attr[tRet[1]][tRet[2].toLowerCase()] += val * 1 || 0
return
}
let aRet = /^(hp|def|atk|mastery|cpct|cdmg|heal|recharge|dmg|phy|shield)(Plus|Pct|Inc)?$/.exec(key)
let aRet = /^(hp|def|atk|mastery|cpct|cdmg|heal|recharge|dmg|phy|shield|speed)(Plus|Pct|Inc)?$/.exec(key)
if (aRet) {
attr[aRet[1]][aRet[2] ? aRet[2].toLowerCase() : 'plus'] += val * 1 || 0
return
@ -177,6 +192,10 @@ let DmgAttr = {
attr.enemy.def += val * 1 || 0
return
}
if (key === 'ignore' || key === 'enemyIgnore') {
attr.enemy.ignore += val * 1 || 0
return
}
if (['vaporize', 'melt', 'burning', 'superConduct', 'swirl', 'electroCharged', 'shatter', 'overloaded', 'bloom', 'burgeon', 'hyperBloom', 'aggravate', 'spread', 'kx', 'fykx'].includes(key)) {
attr[key] += val * 1 || 0

View File

@ -2,63 +2,12 @@
* 伤害计算 - Buff计算
* */
import lodash from 'lodash'
import { Data } from '#miao'
import { ProfileArtis } from '../index.js'
let weaponBuffs = {}
let artisBuffs = {}
// lazy load
setTimeout(async function init () {
weaponBuffs = (await Data.importModule('resources/meta/weapon/index.js', 'miao')).weaponBuffs || {}
artisBuffs = (await Data.importModule('resources/meta/artifact/index.js', 'miao')).calc || {}
})
import { ProfileArtis, ArtifactSet, Weapon } from '../index.js'
let DmgBuffs = {
// 圣遗物Buff
getArtisBuffs (artis = {}) {
let buffs = artisBuffs
let retBuffs = []
ProfileArtis._eachArtisSet(artis, (sets, num) => {
let buff = buffs[sets.name] && buffs[sets.name][num]
if (buff && !buff.isStatic) {
retBuffs.push({
...buff,
title: `${sets.name}${num}` + buff.title
})
}
})
return retBuffs
},
// 武器Buff
getWeaponBuffs (weaponName) {
let weaponCfg = weaponBuffs[weaponName] || []
if (lodash.isPlainObject(weaponCfg)) {
weaponCfg = [weaponCfg]
}
let ret = []
lodash.forEach(weaponCfg, (ds) => {
if (ds.isStatic) {
return true
}
if (!//.test(ds.title)) {
ds.title = `${weaponName}${ds.title}`
}
if (ds.refine) {
ds.data = ds.data || {}
lodash.forEach(ds.refine, (r, key) => {
ds.data[key] = ({ refine }) => r[refine] * (ds.buffCount || 1)
})
}
ret.push(ds)
})
return ret
},
getBuffs (profile, buffs = []) {
let weaponBuffs = DmgBuffs.getWeaponBuffs(profile.weapon?.name || '')
let artisBuffs = DmgBuffs.getArtisBuffs(profile.artis)
getBuffs (profile, buffs = [], game = 'gs') {
let weaponBuffs = DmgBuffs.getWeaponBuffs(profile.weapon, game)
let artisBuffs = DmgBuffs.getArtisBuffs(profile.artis, game)
buffs = lodash.concat(buffs, weaponBuffs, artisBuffs)
let mKey = {
vaporize: '蒸发',
@ -88,6 +37,44 @@ let DmgBuffs = {
})
buffs = lodash.sortBy(buffs, ['sort'])
return buffs
},
// 圣遗物Buff
getArtisBuffs (artis = {}, game = 'gs') {
let retBuffs = []
ProfileArtis._eachArtisSet(artis, (sets, num) => {
let buffs = ArtifactSet.getArtisSetBuff(sets.name, num, game)
if (lodash.isPlainObject(buffs)) {
buffs = [buffs]
}
lodash.forEach(buffs, (buff) => {
if (buff && !buff.isStatic) {
retBuffs.push({
...buff,
title: `${sets.name}${num}` + buff.title
})
}
})
})
return retBuffs
},
// 武器Buff
getWeaponBuffs (wData, game = 'gs') {
let weapon = Weapon.get(wData.name, game)
if (!weapon) {
return false
}
let affix = wData.refine || wData.affix
let weaponCfg = weapon.getWeaponAffixBuffs(affix, false)
let ret = []
lodash.forEach(weaponCfg, (ds) => {
if (ds.isStatic) {
return true
}
ret.push(ds)
})
return ret
}
}
export default DmgBuffs

View File

@ -18,7 +18,8 @@ let DmgCalc = {
attr, // 属性
level, // 面板数据
enemyLv, // 敌人等级
showDetail = false // 是否展示详情
showDetail = false, // 是否展示详情
game
} = data
let calc = ds.calc
@ -64,20 +65,27 @@ let DmgCalc = {
// 防御区
let defNum = (level + 100) / ((level + 100) + (enemyLv + 100) * (1 - enemyDef) * (1 - enemyIgnore))
if (game === 'sr') {
defNum = (200 + level * 10) / ((200 + level * 10) + (200 + enemyLv * 10) * (1 - enemyDef) * (1 - enemyIgnore))
}
// 抗性区
let kx = attr.kx
if (ele === 'swirl') {
kx = attr.fykx
}
kx = 10 - (kx || 0)
let kNum = 0.9
if (kx >= 75) {
kNum = 1 / (1 + 3 * kx / 100)
} else if (kx >= 0) {
kNum = (100 - kx) / 100
if (game === 'sr') {
kNum = (1 + (kx / 100)) * 0.9
} else {
kNum = 1 - kx / 200
if (ele === 'swirl') {
kx = attr.fykx
}
kx = 10 - (kx || 0)
if (kx >= 75) {
kNum = 1 / (1 + 3 * kx / 100)
} else if (kx >= 0) {
kNum = (100 - kx) / 100
} else {
kNum = 1 - kx / 200
}
}
cpctNum = Math.max(0, Math.min(1, cpctNum))
@ -144,13 +152,17 @@ let DmgCalc = {
return ret
},
getDmgFn (data) {
let { showDetail, attr, ds } = data
let { showDetail, attr, ds, game } = data
let { calc } = ds
let dmgFn = function (pctNum = 0, talent = false, ele = false, basicNum = 0, mode = 'talent') {
if (ele) {
ele = erTitle[ele] || ele
}
if (game === 'sr') {
// 星铁meta数据天赋为百分比前数字
pctNum = pctNum * 100
}
return DmgCalc.calcRet({ pctNum, talent, ele, basicNum, mode }, data)
}

View File

@ -78,7 +78,8 @@
</div>
<div class="copyright data-source">
数据源:{{ {miao:'喵喵API', 'enka':'Enka.Network', 'mgg':'MiniGG-API', mys:'米游社', 'hutao':'Hutao-Enka' }[data.source]||data.source }} {{data.updateTime}}
数据源:{{ {miao:'喵喵API', 'enka':'Enka.Network', 'mgg':'MiniGG-API', mys:'米游社', 'hutao':'Hutao-Enka', 'homo':'Mihomo'
}[data.source]||data.source }} {{data.updateTime}}
</div>
{{else}}
{{if custom}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -160,12 +160,24 @@ body {
.i-cdmg {
background-position: -96px 0;
}
.i-stance {
background-position: -64px 0;
}
.i-recharge {
background-position: -112px 0;
}
.i-dmg {
background-position: -128px 0;
}
.i-heal {
background-position: -144px 0;
}
.i-speed {
background-position: -160px 0;
}
.i-effPct {
background-position: -176px 0;
}
.detail.attr li:nth-child(even) {
background: rgba(0, 0, 0, 0.4);
}
@ -821,4 +833,116 @@ body {
line-height: 20px;
color: #bbb;
}
.game-sr .char-talents {
transform: scale(0.8);
transform-origin: top left;
margin: -8px 0 -14px;
}
.game-sr .char-talents .talent-item {
margin: 0 -3px;
}
.game-sr .artis-weapon {
display: none;
}
.game-sr .char-attr .icon i {
background-image: url('./imgs/icon-sr.png');
}
.sr-weapon {
margin: 0 15px 5px 10px;
border-radius: 10px;
background: url("../common/cont/card-bg.png") top left repeat-x;
background-size: auto 150%;
position: relative;
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8);
overflow: hidden;
display: table;
color: #fff;
min-height: 120px;
width: calc(100% - 25px);
}
.sr-weapon .weapon-img {
display: table-cell;
width: 185px;
height: 100%;
min-height: 120px;
background-size: 100% auto;
background-position: 0 5%;
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8);
}
.sr-weapon .weapon-info {
display: table-cell;
padding: 10px 10px 5px 15px;
}
.sr-weapon .weapon-title span {
font-size: 14px;
}
.sr-weapon .weapon-title strong {
color: #d3bc8e;
font-weight: normal;
}
.sr-weapon .weapon-attr {
font-size: 12px;
height: 25px;
line-height: 25px;
display: flex;
}
.sr-weapon .weapon-attr .attr {
padding-left: 22px;
padding-right: 7px;
margin-right: 10px;
position: relative;
line-height: 22px;
height: 22px;
font-size: 12px;
color: #ffe699;
display: inline-block;
border-radius: 4px;
background: rgba(0, 0, 0, 0.5);
text-align: center;
}
.sr-weapon .weapon-attr .attr span {
font-size: 12px;
display: none;
}
.sr-weapon .weapon-attr .attr:before {
content: "";
display: inline-block;
width: 22px;
height: 22px;
background-size: auto 100%;
background-position: top center;
vertical-align: middle;
position: absolute;
left: 0;
top: 0;
}
.sr-weapon .weapon-attr .i-hp:before {
background-image: url('../meta-sr/public/icons/attr-hp.webp');
}
.sr-weapon .weapon-attr .i-atk:before {
background-image: url('../meta-sr/public/icons/attr-atk.webp');
}
.sr-weapon .weapon-attr .i-def:before {
background-image: url('../meta-sr/public/icons/attr-def.webp');
}
.sr-weapon .weapon-desc {
margin-top: 7px;
font-size: 12px;
font-weight: normal;
color: #fff;
white-space: break-spaces;
text-shadow: 0 0 1px rgba(0, 0, 0, 0.7), 1px 1px 3px rgba(0, 0, 0, 0.4);
}
.sr-weapon .weapon-desc nobr {
color: #ffe699;
display: inline-block;
border-radius: 4px;
font-size: 12px;
height: 16px;
line-height: 16px;
background: rgba(0, 0, 0, 0.5);
text-align: center;
padding: 0 3px;
margin: 0 2px;
}
/*# sourceMappingURL=profile-detail.css.map */

View File

@ -7,265 +7,301 @@
{{set weapon = data.weapon}}
{{set dataSource = data.dataSource}}
{{set talentMap = {a: '普攻', e: '战技', q: '爆发'} }}
{{set talentMap = game === 'sr' ? {a: '普攻', e: '战技', t:'天赋', q: '爆发'} : {a: '普攻', e: '战技', q: '爆发'} }}
{{set {imgs, costumeSplash} = data }}
{{set imgs = imgs || {} }}
{{set gameHash = game === 'gs' ? '#':'*' }}
{{block 'main'}}
<div class="basic">
<div class="main-pic"
style="background-image:url({{_res_path}}{{costumeSplash||imgs?.splash}})"></div>
<div class="detail">
<div class="char-name">{{data.name}}</div>
<div class="char-lv">UID {{uid}} - Lv.{{data.level}}
<span class="cons cons-{{data.cons}}">{{data.cons}}命</span></div>
<div>
{{if mode !== 'weapon'}}
<div class="char-talents">
{{each talentMap tName key}}
{{set talent = data.talent[key] || {} }}
<div class="talent-item">
<div class="talent-icon
<div class="game-{{game}}">
<div class="basic">
<div class="main-pic"
style="background-image:url({{_res_path}}{{costumeSplash||imgs?.splash}})"></div>
<div class="detail">
<div class="char-name">{{data.name}}</div>
<div class="char-lv">UID {{uid}} - Lv.{{data.level}}
<span class="cons cons-{{data.cons}}">{{data.cons}}命</span></div>
<div>
{{if mode !== 'weapon'}}
<div class="char-talents">
{{each talentMap tName key}}
{{set talent = data.talent[key] || {} }}
<div class="talent-item">
<div class="talent-icon
{{talent.level > talent.original ? `talent-plus`:``}}
{{talent.original >= 10 ? `talent-crown`:``}}">
<div class="talent-icon-img"
style="background-image:url({{_res_path}}{{imgs[key]}})"></div>
<span>{{talent.level}}</span>
<div class="talent-icon-img"
style="background-image:url({{_res_path}}{{imgs[key]}})"></div>
<span>{{talent.level}}</span>
</div>
</div>
{{/each}}
</div>
<ul class="char-attr">
{{set attrMap = game === 'sr' ? {
hp:'生命值',atk:'攻击力',def:'防御力',speed:'速度',cpct:'暴击率',cdmg:'暴击伤害',dmg:'伤害加成',stance:'击破特效',effPct:'效果命中'
}:{
hp:'生命值',atk:'攻击力',def:'防御力',mastery:'元素精通',cpct:'暴击率',cdmg:'暴击伤害',recharge:'元素充能',dmg:'伤害加成'
} }}
{{set cw = artisDetail?.charWeight || {} }}
{{each attrMap title key}}
<li>
<div class="icon"><i class="i-{{key}}"></i></div>
<div class="title">{{title}}</div>
<div class="weight">
{{if cw[key]}}
<span class="{{cw[key]>=80?'gold':'normal'}}">{{cw[key]}}</span>
{{/if}}
</div>
<div class="value">
{{attr[key]}}
</div>
<div class="value2">
<span class="base">{{attr[key+'Base']}}</span>
<span class="plus">+{{attr[key+'Plus']}}</span>
</div>
</li>
{{/each}}
</ul>
{{else}}
<div class="char-weapon">
<div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div>
<div class="head">
<strong>{{weapon.name}}</strong>
<div class="star star-{{weapon.star}}"></div>
<span>Lv.{{weapon.leve || weapon.level}} <span
class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span></span>
</div>
</div>
{{/each}}
</div>
<ul class="char-attr">
{{set attrMap = {hp:'生命值',atk:'攻击力',def:'防御力',mastery:'元素精通',cpct:'暴击率',cdmg:'暴击伤害',recharge:'元素充能',dmg:'伤害加成'} }}
{{set cw = artisDetail?.charWeight || {} }}
{{each attrMap title key}}
<li>
<div class="icon"><i class="i-{{key}}"></i></div>
<div class="title">{{title}}</div>
<div class="weight">
{{if cw[key]}}
<span class="{{cw[key]>=80?'gold':'normal'}}">{{cw[key]}}</span>
{{/if}}
</div>
<div class="value">
{{attr[key]}}
</div>
<div class="value2">
<span class="base">{{attr[key+'Base']}}</span>
<span class="plus">+{{attr[key+'Plus']}}</span>
</div>
</li>
{{/each}}
</ul>
{{else}}
<div class="char-weapon">
<div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div>
<div class="head">
<strong>{{weapon.name}}</strong>
<div class="star star-{{weapon.star}}"></div>
<span>Lv.{{weapon.leve || weapon.level}} <span
class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span></span>
</div>
</div>
{{/if}}
</div>
</div>
<div class="char-cons">
{{set cons = [1,2,3,4,5,6]}}
{{each cons idx}}
<div class="cons-item">
<div class="talent-icon {{idx * 1 > data.cons * 1 ? 'off' : '' }}">
<div class="talent-icon-img"
style="background-image:url({{_res_path}}{{imgs[`cons${idx}`]}})"></div>
</div>
</div>
{{/each}}
</div>
<div class="data-info">
{{if data.dataSource}}
<span>数据源:{{ {change:"面板变换"}[data.dataSource]||data.dataSource }}</span>
{{/if}}
{{if data.updateTime}}
<span class="time">{{data.updateTime}}</span>
{{/if}}
</div>
</div>
{{if changeProfile}}
<div class="cont">
<div class="cont-footer dmg-desc">
<strong>该面板为非实际数据。当前替换命令:</strong> {{changeProfile}}
</div>
</div>
{{/if}}
<!-- 【 武器+圣遗物列表】 -->
<div>
{{if mode === "profile"}}
{{set ad = artisDetail}}
<div class="artis">
<div>
<div class="item weapon">
<div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div>
<div class="head">
<strong>{{weapon.name}}</strong>
<div class="star star-{{weapon.star}}"></div>
<span>Lv.{{weapon.leve || weapon.level}} <span
class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span></span>
</div>
</div>
<div class="item arti-stat">
<div class="arti-class-title">评分规则:{{ad.classTitle}}</div>
<div class="arti-stat-ret">
<div><strong class="mark-{{ad.markClass}}">{{ad.markClass}}</strong><span>圣遗物评级</span></div>
<div><strong>{{ad.mark}}</strong><span>圣遗物总分</span></div>
</div>
</div>
</div>
{{each ad.artis ds idx}}
<div class="item arti">
{{if ds && ds.name && ds.main && ds.main.key && ds.main.key!="undefined"}}
<div class="arti-icon">
<div class="img" style="background-image:url({{_res_path}}{{ds.img}})"></div>
<span>+{{ds.level}}</span>
</div>
<div class="head">
<strong>{{ds.name}}</strong>
<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">{{artisKeyTitle[ds.main?.key]}}</span><span class="val">+{{ds.main.value}}</span>
</li>
{{each ds.attrs attr}}
{{if attr && attr.key}}
<li class="{{ad.charWeight[attr.key]*1 > 79.9 ?`great`:(ad.charWeight[attr.key]*1>0 ? `useful`:`nouse`)}}">
<span class="title">{{if attr.eff}}<i class="eff">{{attr.eff || ''}}</i>{{/if}}{{if attr.upNum}}<i class="up-num up-{{attr.upNum}}"></i>{{/if}}{{artisKeyTitle[attr.key]}}</span>
<span class="val">+{{attr.value}}</span>
</li>
{{/if}}
{{/each}}
</ul>
</div>
</div>
<div class="char-cons">
{{set cons = [1,2,3,4,5,6]}}
{{each cons idx}}
<div class="cons-item">
<div class="talent-icon {{idx * 1 > data.cons * 1 ? 'off' : '' }}">
<div class="talent-icon-img"
style="background-image:url({{_res_path}}{{imgs[`cons${idx}`]}})"></div>
</div>
</div>
{{/each}}
</div>
<div class="data-info">
{{if data.dataSource}}
<span>数据源:{{ {change:"面板变换"}[data.dataSource]||data.dataSource }}</span>
{{/if}}
{{if data.updateTime}}
<span class="time">{{data.updateTime}}</span>
{{/if}}
</div>
{{/each}}
</div>
{{/if}}
</div>
<!-- 【 伤害表格 】 -->
{{ set {dmgRet, dmgCfg, enemyLv, enemyName, dmgMsg, dmgData} = dmgCalc }}
<div>
{{if mode === "profile"}}
{{if changeProfile}}
<div class="cont">
<div class="cont-footer dmg-desc">
当前评分为<strong>喵喵版评分规则</strong>,分值仅供参考与娱乐。可使用<strong>#{{data.abbr}}圣遗物</strong>来查看评分详情
<strong>该面板为非实际数据。当前替换命令:</strong> {{changeProfile}}
</div>
</div>
{{/if}}
{{if dmgData?.length > 0}}
<div class="dmg-cont dmg-list cont">
<div class="cont-title">
伤害计算<span>目标为{{enemyLv}}级{{enemyName||'小宝'}},如需调整等级可使用 #敌人等级{{enemyLv}} 来进行设置</span>
</div>
<div class="cont-table">
<div class="tr thead">
<div class="title dmg-idx">#</div>
<div class="title dmg-title">伤害类型</div>
<div>暴击伤害</div>
<div>平均伤害(计算暴击率)</div>
<!-- 【 武器+圣遗物列表】 -->
<div>
{{if game === 'sr'}}
<div class="sr-weapon">
<div class="weapon-img" style="background-image:url({{_res_path}}{{weapon.splash}})"></div>
<div class="weapon-info">
<div class="weapon-title">
<strong>{{weapon.name}}</strong>
<span>Lv.{{weapon.level}}</span>
<span>叠影{{weapon.affix}}阶</span>
</div>
<div class="weapon-attr">
{{set a = weapon.attrs}}
<div class="attr i-hp"><span>生命</span>{{a.hp}}</div>
<div class="attr i-atk"><span>攻击</span>{{a.atk}}</div>
<div class="attr i-def"><span>防御</span>{{a.def}}</div>
</div>
<div class="weapon-desc">{{@weapon.desc?.desc}}</div>
</div>
{{each dmgData dmg idx}}
<div class="dmg tr">
<div class="title dmg-idx">{{idx+1}}</div>
<div class="title dmg-title">{{dmg.title}}</div>
{{if dmg.dmg === "NaN"}}
<div class="value value-full">{{dmg.avg}}{{dmg.unit}}</div>
<div class="value value-none"></div>
{{else}}
<div class="value">{{dmg.dmg}}{{dmg.unit}}</div>
<div class="value">{{dmg.avg}}{{dmg.unit}}</div>
</div>
{{/if}}
{{if mode === "profile"}}
{{set ad = artisDetail}}
<div class="artis">
{{ if game === 'gs' }}
<div class="artis-weapon">
<div class="item weapon">
<div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div>
<div class="head">
<strong>{{weapon.name}}</strong>
<div class="star star-{{weapon.star}}"></div>
<span>Lv.{{weapon.leve || weapon.level}} <span
class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span></span>
</div>
</div>
<div class="item arti-stat">
<div class="arti-class-title">评分规则:{{ad.classTitle}}</div>
<div class="arti-stat-ret">
<div><strong class="mark-{{ad.markClass}}">{{ad.markClass}}</strong><span>圣遗物评级</span></div>
<div><strong>{{ad.mark}}</strong><span>圣遗物总分</span></div>
</div>
</div>
</div>
{{/if}}
{{each ad.artis ds idx}}
<div class="item arti">
{{if ds && ds.name && ds.main && ds.main.key && ds.main.key!="undefined"}}
<div class="arti-icon">
<div class="img" style="background-image:url({{_res_path}}{{ds.img}})"></div>
<span>+{{ds.level}}</span>
</div>
<div class="head">
<strong>{{ds.abbr || ds.name}}</strong>
<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">{{artisKeyTitle[ds.main?.key]}}</span><span class="val">+{{ds.main.value}}</span>
</li>
{{each ds.attrs attr}}
{{if attr && attr.key}}
<li class="{{ad.charWeight[attr.key]*1 > 79.9 ?`great`:(ad.charWeight[attr.key]*1>0 ? `useful`:`nouse`)}}">
<span class="title">{{if attr.eff}}<i class="eff">{{attr.eff || ''}}</i>{{/if}}{{if attr.upNum}}<i
class="up-num up-{{attr.upNum}}"></i>{{/if}}{{artisKeyTitle[attr.key] || attr.key}}</span>
<span class="val">+{{attr.value}}</span>
</li>
{{/if}}
{{/each}}
</ul>
{{/if}}
</div>
{{/each}}
</div>
<div class="cont-footer dmg-desc">
使用命令<strong>#{{data.abbr}}伤害</strong>可以查看伤害详情,使用命令<strong>#角色面板帮助</strong>可查看帮助说明
</div>
{{/if}}
</div>
{{/if}}
</div>
<!-- 【 伤害变化详情 】 -->
<div>
{{if mode === "dmg"}}
{{if dmgCfg && dmgCfg.attr && dmgCfg.attr.length>0 && dmgRet}}
<div class="dmg-calc dmg-cont cont">
<div class="cont-title">
词条伤害计算<span>#{{data.abbr}}伤害{{dmgCfg.userIdx+1}}: 当前计算为[{{dmgCfg.title}}]</span>
<!-- 【 伤害表格 】 -->
{{ set {dmgRet, dmgCfg, enemyLv, enemyName, dmgMsg, dmgData} = dmgCalc }}
<div>
{{if game === 'gs'}}
{{if mode === "profile"}}
<div class="cont">
<div class="cont-footer dmg-desc">
当前评分为<strong>喵喵版评分规则</strong>,分值仅供参考与娱乐。可使用<strong>{{gameHash}}{{data.abbr}}圣遗物</strong>来查看评分详情
</div>
</div>
<div class="cont-table">
<div class="tr thead ">
<div class="td">词条变化</div>
{{each dmgCfg.attr attr}}
<div class="td">
<strong>{{attr.title}}</strong>
<span>+{{attr.text}}</span>
{{/if}}
{{else}}
<div class="cont">
<div class="cont-footer dmg-desc">
<strong>伤害计算、圣遗物评分及词条数功能尚未完成...</strong>
</div>
</div>
{{/if}}
{{if dmgData?.length > 0}}
<div class="dmg-cont dmg-list cont">
<div class="cont-title">
伤害计算<span>目标为{{enemyLv}}级{{enemyName||'小宝'}}{{if game==='gs'}},如需调整等级可使用 #敌人等级{{enemyLv}} 来进行设置{{/if}}</span>
</div>
<div class="cont-table">
<div class="tr thead">
<div class="title dmg-idx">#</div>
<div class="title dmg-title">伤害类型</div>
<div>暴击伤害</div>
<div>期望伤害</div>
</div>
{{each dmgData dmg idx}}
<div class="dmg tr">
<div class="title dmg-idx">{{idx+1}}</div>
<div class="title dmg-title">{{dmg.title}}</div>
{{if !dmg.dmg || dmg.dmg === "NaN"}}
<div class="value value-full">{{dmg.avg}}{{dmg.unit}}</div>
<div class="value value-none"></div>
{{else}}
<div class="value">{{dmg.dmg}}{{dmg.unit}}</div>
<div class="value">{{dmg.avg}}{{dmg.unit}}</div>
{{/if}}
</div>
{{/each}}
</div>
{{each dmgRet row rowIdx}}
<div class="tr">
<div class="title">
<strong>{{dmgCfg.attr[rowIdx].title}}</strong>
<span>-{{dmgCfg.attr[rowIdx].text}}</span>
</div>
{{each row cell colIdx}}
{{if cell.type === "na"}}
<div class="td na">
<strong>-</strong>
<span>{{dmgCfg.basicRet.avg}}{{dmgCfg.basicRet.dmg!="NaN"?`/${dmgCfg.basicRet.dmg}`:''}}</span>
</div>
{{else}}
<div class="td {{cell.type}}">
<strong>{{cell.val}}</strong>
<div class="cont-footer dmg-desc">
使用命令<strong>{{gameHash}}{{data.abbr}}伤害</strong>可以查看伤害详情,使用命令<strong>#角色面板帮助</strong>可查看帮助说明
</div>
</div>
{{/if}}
</div>
<span>{{cell.avg}}{{cell.dmg!="NaN"?`/${cell.dmg}`:''}}</span>
<!-- 【 伤害变化详情 】 -->
<div>
{{if mode === "dmg"}}
{{if dmgCfg && dmgCfg.attr && dmgCfg.attr.length>0 && dmgRet}}
<div class="dmg-calc dmg-cont cont">
<div class="cont-title">
词条伤害计算<span>{{gameHash}}{{data.abbr}}伤害{{dmgCfg.userIdx+1}}: 当前计算为[{{dmgCfg.title}}]</span>
</div>
<div class="cont-table">
<div class="tr thead ">
<div class="td">词条变化</div>
{{each dmgCfg.attr attr}}
<div class="td">
<strong>{{attr?.title}}</strong>
<span>+{{attr?.text}}</span>
</div>
{{/each}}
</div>
{{each dmgRet row rowIdx}}
<div class="tr">
<div class="title">
<strong>{{dmgCfg.attr[rowIdx].title}}</strong>
<span>-{{dmgCfg.attr[rowIdx].text}}</span>
</div>
{{each row cell colIdx}}
{{if cell.type === "na"}}
<div class="td na">
<strong>-</strong>
<span>{{dmgCfg.basicRet.avg}}{{(dmgCfg.basicRet.dmg&&dmgCfg.basicRet.dmg!="NaN")?`/${dmgCfg.basicRet.dmg}`:''}}</span>
</div>
{{else}}
<div class="td {{cell.type}}">
<strong>{{cell.val}}</strong>
<span>{{cell.avg}}{{cell.dmg!="NaN"?`/${cell.dmg}`:''}}</span>
</div>
{{/if}}
{{/each}}
</div>
{{/if}}
{{/each}}
</div>
{{/each}}
</div>
<div class="cont-footer dmg-desc">
<ul>
<li>大数字的含义为圣遗物副词条置换后<strong>平均伤害</strong>的变化,下方的详情数字为<strong>平均伤害</strong>/<strong>暴击伤害</strong></li>
<li>关于<strong>平均伤害</strong>:是将暴击率计算在内的伤害期望,能反映综合的输出能力,不等于实际伤害数字。</li>
<li>可用于评估当前面板下圣遗物副词条的侧重方向。实际游戏情况更加复杂,结果供参考~</li>
<li>如需更换计算的伤害类型,可使用命令 <strong>#{{data.abbr}}伤害+序号</strong>来切换,序号参见伤害计算板块</li>
</ul>
</div>
</div>
{{/if}}
<div class="dmg-cont dmg-msg cont">
<div class="cont-title">Buff列表<span>部分Buff的触发条件以及层数可能影响实际伤害结果</span></div>
<div class="cont-table">
{{each dmgMsg msg}}
<div class="tr">
<div class="th">{{msg[0]}}</div>
<div class="td">{{msg[1]}}</div>
<div class="cont-footer dmg-desc">
<ul>
<li>大数字的含义为圣遗物副词条置换后<strong>平均伤害</strong>的变化,下方的详情数字为<strong>平均伤害</strong>/<strong>暴击伤害</strong></li>
<li>关于<strong>平均伤害</strong>:是将暴击率计算在内的伤害期望,能反映综合的输出能力,不等于实际伤害数字。</li>
<li>可用于评估当前面板下圣遗物副词条的侧重方向。实际游戏情况更加复杂,结果供参考~</li>
<li>如需更换计算的伤害类型,可使用命令 <strong>{{gameHash}}{{data.abbr}}伤害+序号</strong>来切换,序号参见伤害计算板块</li>
</ul>
</div>
{{/each}}
</div>
</div>
{{/if}}
</div>
{{/if}}
<div class="dmg-cont dmg-msg cont">
<div class="cont-title">Buff列表<span>部分Buff的触发条件以及层数可能影响实际伤害结果</span></div>
<div class="cont-table">
{{each dmgMsg msg}}
<div class="tr">
<div class="th">{{msg[0]}}</div>
<div class="td">{{msg[1]}}</div>
</div>
{{/each}}
</div>
</div>
{{/if}}
</div>
</div>
{{/block}}

View File

@ -183,6 +183,8 @@ body {
background-position: @i*-4 0;
}
.i-cpct {
background-position: @i*-5 0;
}
@ -190,6 +192,9 @@ body {
.i-cdmg {
background-position: @i*-6 0;
}
.i-stance {
background-position: @i*-4 0;
}
.i-recharge {
background-position: @i*-7 0;
@ -199,6 +204,18 @@ body {
background-position: @i*-8 0;
}
.i-heal {
background-position: @i*-9 0;
}
.i-speed {
background-position: @i*-10 0;
}
.i-effPct {
background-position: @i*-11 0;
}
.detail.attr {
li {
&:nth-child(even) {
@ -1029,4 +1046,145 @@ body {
font-size: 13px;
line-height: 20px;
color: #bbb;
}
.game-sr {
.char-talents {
transform: scale(.8);
transform-origin: top left;
margin: -8px 0 -14px;
.talent-item {
margin: 0 -3px;
}
}
.artis-weapon {
display: none;
}
.char-attr {
.icon i {
background-image: url('./imgs/icon-sr.png');
}
}
}
.sr-weapon {
margin: 0 15px 5px 10px;
border-radius: 10px;
background: url("../common/cont/card-bg.png") top left repeat-x;
background-size: auto 150%;
position: relative;
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8);
overflow: hidden;
display: table;
color: #fff;
min-height: 120px;
width: calc(100% - 25px);
.weapon-img {
display: table-cell;
width: 185px;
height: 100%;
min-height: 120px;
background-size: 100% auto;
background-position: 0 5%;
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8);
}
.weapon-info {
display: table-cell;
padding: 10px 10px 5px 15px;
}
.weapon-title {
span {
font-size: 14px;
}
strong {
color: #d3bc8e;
font-weight: normal;
}
}
.weapon-attr {
font-size: 12px;
height: 25px;
line-height: 25px;
display: flex;
.attr {
padding-left: 22px;
padding-right: 7px;
margin-right: 10px;
position: relative;
line-height: 22px;
height: 22px;
font-size: 12px;
color: #ffe699;
display: inline-block;
border-radius: 4px;
background: rgba(0, 0, 0, 0.5);
text-align: center;
span {
font-size: 12px;
display: none;
}
&:before {
content: "";
display: inline-block;
width: 22px;
height: 22px;
background-size: auto 100%;
background-position: top center;
vertical-align: middle;
position: absolute;
left: 0;
top: 0;
}
}
.i-hp:before {
background-image: url('../meta-sr/public/icons/attr-hp.webp')
}
.i-atk:before {
background-image: url('../meta-sr/public/icons/attr-atk.webp')
}
.i-def:before {
background-image: url('../meta-sr/public/icons/attr-def.webp')
}
}
.weapon-desc {
margin-top: 7px;
font-size: 12px;
font-weight: normal;
color: #fff;
white-space: break-spaces;
text-shadow: 0 0 1px rgba(0, 0, 0, 0.7), 1px 1px 3px rgba(0, 0, 0, 0.4);
nobr {
color: #ffe699;
display: inline-block;
border-radius: 4px;
font-size: 12px;
height: 16px;
line-height: 16px;
background: rgba(0, 0, 0, 0.5);
text-align: center;
padding: 0 3px;
margin: 0 2px;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

View File

@ -1,21 +1,22 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link rel="shortcut icon" href="#"/>
<link rel="preload" href="{{_miao_path}}common/font/HYWH-65W.woff" as="font" type="font/woff">
<link rel="preload" href="{{_miao_path}}common/font/NZBZ.woff" as="font" type="font/woff">
<link rel="preload" href="{{_miao_path}}common/font/tttgbnumber.woff" as="font" type="font/woff">
<link rel="stylesheet" type="text/css" href="{{_miao_path}}common/common.css"/>
<title>miao-plugin</title>
{{block 'css'}}
{{/block}}
</head>
<body class="elem-{{element||elem||`hydro`}} {{displayMode || mode || `default`}}-mode {{bodyClass}}" {{sys.scale}}>
<div class="container elem-bg" id="container">
{{block 'main'}}{{/block}}
<div class="copyright">{{@copyright || sys?.copyright}}</div>
</div>
</body>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link rel="shortcut icon" href="#"/>
<link rel="preload" href="{{_miao_path}}common/font/HYWH-65W.woff" as="font" type="font/woff">
<link rel="preload" href="{{_miao_path}}common/font/NZBZ.woff" as="font" type="font/woff">
<link rel="preload" href="{{_miao_path}}common/font/tttgbnumber.woff" as="font" type="font/woff">
<link rel="stylesheet" type="text/css" href="{{_miao_path}}common/common.css"/>
<title>miao-plugin</title>
{{block 'css'}}
{{/block}}
</head>
{{set elemCls = {火:'pyro',冰:'cryo',风:'anemo',雷:'electro',量子:'electro',虚数:'geo',物理:'hydro', }[element||elem] || element || elem || 'hydro' }}
<body class="elem-{{elemCls}} {{displayMode || mode || `default`}}-mode {{bodyClass}}" {{sys.scale}}>
<div class="container elem-bg" id="container">
{{block 'main'}}{{/block}}
<div class="copyright">{{@copyright || sys?.copyright}}</div>
</div>
</body>
</html>

View File

@ -0,0 +1,155 @@
let attr = (key, val) => {
let data = {}
data[key] = val
return {
isStatic: true,
data
}
}
export default {
云无留迹的过客: {
2: attr('heal', 10)
},
野穗伴行的快枪手: {
2: attr('atkPct', 12),
4: [attr('speed', 6), {
title: '普攻伤害提高10%',
data: {
aDmg: 10
}
}]
},
净庭教宗的圣骑士: {
2: attr('defPct', 15),
4: {
title: '护盾强效提高20%',
data: {
shield: 20
}
}
},
密林卧雪的猎人: {
2: attr('ice', 10),
4: {
title: '释放终结技后2回合爆伤提高25%',
data: {
cdmg: 25
}
}
},
街头出身的拳王: {
2: attr('phy', 10),
4: {
title: '攻击或被攻击5层Buff提高攻击力25%',
data: {
atkPct: 25
}
}
},
熔岩锻铸的火匠: {
2: attr('fire', 10),
4: {
title: '战技造成的伤害提高12%释放终结技下一次的火属性伤害提高12%',
data: {
eDmg: 12,
dmg: 12 // todo: 检查属性
}
}
},
繁星璀璨的天才: {
2: attr('quantum', 10),
4: {
title: '对有量子弱点的目标造成伤害时无视其20%的防御力',
data: {
ignore: 20
}
}
},
激奏雷电的乐队: {
2: attr('elec', 10),
4: {
title: '释放战绩时攻击力提高20%',
data: {
atkPct: 20
}
}
},
晨昏交界的翔鹰: {
2: attr('wind', 10)
},
流星追迹的怪盗: {
2: attr('stance', 16),
4: attr('stance', 16)
},
盗匪荒漠的废土客: {
2: attr('imaginary', 10),
4: {
title: '对陷入负面效果的目标的暴击率提高10%对禁锢状态的目标暴击率提高20%',
data: {
cpct: 10
}
}
},
太空封印站: {
2: [attr('atkPct', 12), {
title: '速度大于等于120提高攻击力12%',
check: ({ calc, attr }) => calc(attr.speed) > 120,
data: {
atkPct: 12
}
}]
},
不老者的仙舟: {
2: [attr('hpPct', 12), {
title: '速度大于等于120提高攻击力8%',
check: ({ calc, attr }) => calc(attr.speed) > 120,
data: {
atkPct: 8
}
}]
},
泛银河商业公司: {
2: [attr('effPct', 12), {
title: '基于效果命中提高攻击力[atkPct]%',
data: {
atkPct: ({ calc, attr }) => Math.min(25, calc(attr.effPct) / 4 || 0)
}
}]
},
筑城者的贝洛伯格: {
2: [attr('defPct', 12), {
title: '效果命中大于50%时提高防御力15%',
check: ({ calc, attr }) => calc(attr.effPct) > 50,
data: {
defPct: 15
}
}]
},
星体差分机: {
2: attr('cdmg', 16)
},
停转的萨尔索图: {
2: [attr('cpct', 8), {
title: '终结技与追加攻击造成的伤害提高15%',
check: ({ attr, calc }) => {
return calc(attr.cpct) > 50
},
data: {
qDmg: 15,
a3Dmg: 15
}
}]
},
盗贼公国塔利亚: {
2: [attr('stance', 16), {
title: '速度大于145时击破特攻提高20%',
check: ({ calc, attr }) => calc(attr.speed) > 145,
data: {
stance: 20
}
}]
},
生命的翁瓦克: {
2: attr('recharge', 5)
}
}

View File

@ -0,0 +1,36 @@
import { Data } from '#miao'
import lodash from 'lodash'
import artisBuffs from './calc.js'
let data = Data.readJSON('/resources/meta-sr/artifact/data.json', 'miao')
let meta = Data.readJSON('/resources/meta-sr/artifact/meta.json', 'miao')
let artiMap = {}
let idMap = {}
let artiSetMap = {}
lodash.forEach(data, (setData) => {
let artiSet = {
name: setData.name,
effect: setData.skill,
sets: {}
}
artiSetMap[setData.name] = artiSet
lodash.forEach(setData.idxs, (ds, idx) => {
artiMap[ds.name] = {
...ds,
set: setData.name,
setId: setData.id,
idx
}
idMap[ds.name] = artiMap[ds.name]
lodash.forEach(ds.ids, (star, id) => {
idMap[id] = artiMap[ds.name]
})
artiSet.sets[idx] = ds.name
})
})
export const metaData = meta
export { artiMap, idMap, artisBuffs, artiSetMap }
export * from './meta.js'

View File

@ -0,0 +1,81 @@
import lodash from 'lodash'
import { Format } from '#miao'
import { attrPct, basicNum } from '../../meta/artifact/index.js'
export const mainAttr = {
3: 'atk,def,hp,cpct,cdmg,heal,effPct'.split(','),
4: 'atk,def,hp,speed'.split(','),
5: 'atk,def,hp,dmg'.split(','),
6: 'atk,def,hp,recharge,stance'.split(',')
}
export const subAttr = 'atk,atkPlus,def,defPlus,hp,hpPlus,speed,cpct,cdmg,effPct,effDef,stance'.split(',')
/**
* 圣遗物词条配置
* @[]value 副词条单次提升值最大档位
* @[]valueMin 副词条单次提升最小值
* @[]calc 伤害计算时变更的字段type
* @[]type 词条的类型 normal:普通字段 plus:小词条
* @[]base 词条类型为小词条时对应的大词条
* @[]text 展示文字
*/
const attrMap = {
atk: { title: '大攻击', format: 'pct', calc: 'pct', value: 4.32 },
atkPlus: { title: '小攻击', format: 'comma', value: 21 },
def: { title: '大防御', format: 'pct', calc: 'pct', value: 5.4 },
defPlus: { title: '小防御', format: 'comma', value: 21 },
hp: { title: '大生命', format: 'pct', calc: 'pct', value: 4.32 },
hpPlus: { title: '小生命', format: 'comma', value: 42 },
speed: { title: '速度', format: 'comma', calc: 'plus', value: 2.6 },
cpct: { title: '暴击率', format: 'pct', calc: 'plus', value: 3.24 },
cdmg: { title: '暴击伤害', format: 'pct', calc: 'plus', value: 6.48 },
recharge: { title: '充能效率', format: 'pct', calc: 'plus' },
dmg: { title: '伤害加成', format: 'pct' },
heal: { title: '治疗加成', format: 'pct' },
stance: { title: '击破特攻', format: 'pct', value: 6.48 },
effPct: { title: '效果命中', format: 'pct', value: 4.32 },
effDef: { title: '效果抵抗', format: 'pct', value: 4.32 }
}
lodash.forEach(attrMap, (attr, key) => {
// 设置value
if (!attr.value) {
return true
}
// 设置type
attr.base = { hpPlus: 'hp', atkPlus: 'atk', defPlus: 'def' }[key]
attr.type = attr.base ? 'plus' : 'normal'
// 设置展示文字
attr.text = Format[attr.format](attr.value, 2)
})
export { attrMap }
export const abbr = {
快枪手的野穗毡帽: '快枪手的毡帽',
快枪手的粗革手套: '快枪手的手套',
快枪手的猎风披肩: '快枪手的披肩',
快枪手的铆钉马靴: '快枪手的铆钉靴',
废土客的呼吸面罩: '废土客的面罩',
废土客的荒漠终端: '废土客的终端',
废土客的修士长袍: '废土客的长袍',
废土客的动力腿甲: '废土客的腿甲',
'「黑塔」的空间站点': '黑塔的空间站点',
'「黑塔」的漫历轨迹': '黑塔的漫历轨迹',
罗浮仙舟的天外楼船: '罗浮仙舟的楼船',
罗浮仙舟的建木枝蔓: '罗浮仙舟的建木',
贝洛伯格的存护堡垒: '贝洛伯格的堡垒',
贝洛伯格的铁卫防线: '贝洛伯格的防线',
螺丝星的机械烈阳: '螺丝星的烈阳',
螺丝星的环星孔带: '螺丝星的孔带',
萨尔索图的移动城市: '萨尔索图的城市',
萨尔索图的晨昏界线: '萨尔索图的界线',
塔利亚的钉壳小镇: '塔利亚的小镇',
塔利亚的裸皮电线: '塔利亚的电线',
翁瓦克的诞生之岛: '翁瓦克的诞生岛',
翁瓦克的环岛海岸: '翁瓦克的海岸'
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
import lodash from 'lodash'
let alias = {
三月七: '三月,相遇之缘,37,3月7',
丹恒: '单恒,单桓,冷面,小青龙,冷面小青龙',
佩拉: '佩菈',
停云: '',
克拉拉: '',
卡夫卡: '亲妈',
姬子: '',
娜塔莎: '纳塔莎,纳塔沙,纳塔沙',
布洛妮娅: '大鸭鸭,鸭鸭,板鸭,布洛尼亚,布洛妮亚,布洛尼娅',
希儿: '希尔,蝴蝶,云天明',
希露瓦: '希璐瓦',
彦卿: '延卿,闫卿,彦清,彦青',
景元: '景原,景源,神君发射器',
杰帕德: '',
桑博: '桑柏,桑伯',
瓦尔特: '老杨,杨叔,瓦尔特杨',
白露: '小龙人',
素裳: '',
罗刹: '罗沙,罗杀',
艾丝妲: '宇宙级富婆',
虎克: '胡可,虎克大人,漆黑的虎克,漆黑的虎克大人,鼹鼠党,鼹鼠党老大',
银狼: '小鸭鸭,小板鸭,黑客,骇客,骇兔',
阿兰: '',
青雀: '赌神,赌圣,青鹊',
黑塔: ''
}
let aliasMap = {}
lodash.forEach(alias, (txt, char) => {
if (!txt) {
return true
}
lodash.forEach(txt.split(','), (t) => {
aliasMap[t] = char
})
})
export { aliasMap }

View File

@ -398,6 +398,48 @@
}
},
"tree": {
"1001201": {
"key": "ice",
"value": 3.1999999890103936
},
"1001202": {
"key": "def",
"value": 5.000000004656613
},
"1001203": {
"key": "ice",
"value": 3.1999999890103936
},
"1001204": {
"key": "effDef",
"value": 4.00000000372529
},
"1001205": {
"key": "ice",
"value": 4.799999948590994
},
"1001206": {
"key": "effDef",
"value": 6.0000000055879354
},
"1001207": {
"key": "def",
"value": 7.499999972060323
},
"1001208": {
"key": "ice",
"value": 4.799999948590994
},
"1001209": {
"key": "ice",
"value": 6.399999978020787
},
"1001210": {
"key": "def",
"value": 10.000000009313226
}
},
"treeData": {
"877640": {
"id": 877640,
"type": "skill",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 831 KiB

After

Width:  |  Height:  |  Size: 554 KiB

View File

@ -0,0 +1,39 @@
export const details = [{
title: 'A普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E战技主目标伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['技能伤害'], 'e')
}, {
title: 'Q终结技伤害',
dmg: ({ talent }, dmg) => dmg(talent.q['技能伤害'], 'q')
}, {
title: '减速目标终结技伤害',
dmg: ({ talent }, dmg) => dmg(talent.q['技能伤害'] + talent.q['减速目标q伤害倍率提高'], 'q')
}]
export const mainAttr = 'atk,cpct,cdmg'
export const buffs = [{
title: '丹恒天赋:丹恒成为我方技能的目标时提高抗性穿透[kx]%',
data: {
kx: ({ talent }) => talent.t['风抗性穿透']
}
}, {
title: '丹恒秘技使用秘技提高40%攻击力',
data: {
atkPct: 40
}
}, {
title: '丹恒1命击中目标生命值大于50%暴击率提高12%',
cons: 1,
data: {
cpct: 12
}
}, {
title: '行迹-罡风普攻对减速状态下的敌方目标造成的伤害提高40%',
tree: 3,
data: {
aDmg: 40
}
}]

View File

@ -377,6 +377,48 @@
}
},
"tree": {
"1002201": {
"key": "wind",
"value": 3.1999999890103936
},
"1002202": {
"key": "atk",
"value": 4.00000000372529
},
"1002203": {
"key": "wind",
"value": 3.1999999890103936
},
"1002204": {
"key": "def",
"value": 5.000000004656613
},
"1002205": {
"key": "wind",
"value": 4.799999948590994
},
"1002206": {
"key": "atk",
"value": 6.0000000055879354
},
"1002207": {
"key": "wind",
"value": 4.799999948590994
},
"1002208": {
"key": "def",
"value": 7.499999972060323
},
"1002209": {
"key": "atk",
"value": 8.00000000745058
},
"1002210": {
"key": "wind",
"value": 6.399999978020787
}
},
"treeData": {
"124180": {
"id": 124180,
"type": "buff",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 870 KiB

After

Width:  |  Height:  |  Size: 452 KiB

View File

@ -377,6 +377,48 @@
}
},
"tree": {
"1106201": {
"key": "ice",
"value": 3.1999999890103936
},
"1106202": {
"key": "atk",
"value": 4.00000000372529
},
"1106203": {
"key": "ice",
"value": 3.1999999890103936
},
"1106204": {
"key": "effPct",
"value": 4.00000000372529
},
"1106205": {
"key": "ice",
"value": 4.799999948590994
},
"1106206": {
"key": "atk",
"value": 6.0000000055879354
},
"1106207": {
"key": "ice",
"value": 4.799999948590994
},
"1106208": {
"key": "effPct",
"value": 6.0000000055879354
},
"1106209": {
"key": "atk",
"value": 8.00000000745058
},
"1106210": {
"key": "ice",
"value": 6.399999978020787
}
},
"treeData": {
"660958": {
"id": 660958,
"type": "skill",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 855 KiB

After

Width:  |  Height:  |  Size: 534 KiB

View File

@ -0,0 +1,31 @@
import { Format } from '#miao'
export const details = [{
title: '普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E赐福提高攻击力上限',
dmg: ({ attr, calc, talent }) => {
return {
avg: calc(attr.atk) * talent.e['攻击力上限']
}
}
}, {
title: 'Q伤害提高',
dmg: ({ talent }) => {
return {
avg: Format.percent(talent.q['伤害提高']),
type: 'text'
}
}
}]
export const mainAttr = 'atk,cpct,cdmg'
export const buffs = [{
title: '行迹-止厄普攻造成的伤害提高40%',
tree: 2,
data: {
aDmg: 40
}
}]

View File

@ -398,6 +398,48 @@
}
},
"tree": {
"1202201": {
"key": "atk",
"value": 4.00000000372529
},
"1202202": {
"key": "def",
"value": 5.000000004656613
},
"1202203": {
"key": "atk",
"value": 4.00000000372529
},
"1202204": {
"key": "elec",
"value": 3.1999999890103936
},
"1202205": {
"key": "atk",
"value": 6.0000000055879354
},
"1202206": {
"key": "def",
"value": 7.499999972060323
},
"1202207": {
"key": "atk",
"value": 6.0000000055879354
},
"1202208": {
"key": "elec",
"value": 4.799999948590994
},
"1202209": {
"key": "def",
"value": 10.000000009313226
},
"1202210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"264650": {
"id": 264650,
"type": "buff",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 KiB

After

Width:  |  Height:  |  Size: 353 KiB

View File

@ -0,0 +1,29 @@
export const details = [{
title: 'A普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E战技伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['技能伤害'], 'e')
}, {
title: 'E反击伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['反击伤害'], 'e')
}, {
title: 'Q反击伤害',
dmg: ({ talent }, dmg) => dmg(talent.q['伤害倍率提高'] + talent.t['反击伤害'], 't')
}]
export const mainAttr = 'atk,cpct,cdmg,speed'
export const buffs = [{
title: '克拉拉2命施放终结技后攻击力提高30%',
cons: 2,
data: {
atkPct: 30
}
}, {
title: '行迹-复仇史瓦罗的反击造成的伤害提高30%',
tree: 3,
data: {
tDmg: 30
}
}]

View File

@ -398,6 +398,48 @@
}
},
"tree": {
"1107201": {
"key": "atk",
"value": 4.00000000372529
},
"1107202": {
"key": "phy",
"value": 3.1999999890103936
},
"1107203": {
"key": "atk",
"value": 4.00000000372529
},
"1107204": {
"key": "hp",
"value": 4.00000000372529
},
"1107205": {
"key": "atk",
"value": 6.0000000055879354
},
"1107206": {
"key": "phy",
"value": 4.799999948590994
},
"1107207": {
"key": "atk",
"value": 6.0000000055879354
},
"1107208": {
"key": "hp",
"value": 6.0000000055879354
},
"1107209": {
"key": "phy",
"value": 6.399999978020787
},
"1107210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"864032": {
"id": 864032,
"type": "buff",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 KiB

After

Width:  |  Height:  |  Size: 270 KiB

View File

@ -458,6 +458,48 @@
}
},
"tree": {
"1005201": {
"key": "atk",
"value": 4.00000000372529
},
"1005202": {
"key": "stance",
"value": 5.299999983981252
},
"1005203": {
"key": "atk",
"value": 4.00000000372529
},
"1005204": {
"key": "hp",
"value": 4.00000000372529
},
"1005205": {
"key": "atk",
"value": 6.0000000055879354
},
"1005206": {
"key": "stance",
"value": 8.00000000745058
},
"1005207": {
"key": "atk",
"value": 6.0000000055879354
},
"1005208": {
"key": "hp",
"value": 6.0000000055879354
},
"1005209": {
"key": "stance",
"value": 10.699999961070716
},
"1005210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"227636": {
"id": 227636,
"type": "skill",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 KiB

After

Width:  |  Height:  |  Size: 287 KiB

View File

@ -0,0 +1,46 @@
export const details = [{
title: 'A普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E战技主目标伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['主目标伤害'], 'e')
}, {
title: 'Q终结技伤害',
dmg: ({ talent }, dmg) => dmg(talent.q['技能伤害'], 'q')
}, {
title: '天赋追击伤害',
dmg: ({ talent }, dmg) => dmg(talent.t['技能伤害'], 't')
}]
export const mainAttr = 'atk,cpct,cdmg,speed'
export const buffs = [{
title: '姬子秘技释放领域使敌方受到伤害提高10%',
data: {
dmg: 10
}
}, {
title: '姬子1命对生命小于50%的敌人伤害提高15%',
cons: 1,
data: {
dmg: 15
}
}, {
title: '希儿2命释放战技后2层Buff速度提高50%',
cons: 2,
data: {
speedPct: 50
}
}, {
title: '行迹-灼热战技对灼烧状态下的敌方目标造成的伤害提高20%',
tree: 2,
data: {
eDmg: 20
}
}, {
title: '行迹-道标生命值大于80%时提高暴击率15%',
tree: 3,
data: {
cpct: 15
}
}]

View File

@ -377,13 +377,55 @@
}
},
"tree": {
"1003201": {
"key": "fire",
"value": 3.1999999890103936
},
"1003202": {
"key": "atk",
"value": 4.00000000372529
},
"1003203": {
"key": "fire",
"value": 3.1999999890103936
},
"1003204": {
"key": "effDef",
"value": 4.00000000372529
},
"1003205": {
"key": "fire",
"value": 4.799999948590994
},
"1003206": {
"key": "atk",
"value": 6.0000000055879354
},
"1003207": {
"key": "fire",
"value": 4.799999948590994
},
"1003208": {
"key": "effDef",
"value": 6.0000000055879354
},
"1003209": {
"key": "atk",
"value": 8.00000000745058
},
"1003210": {
"key": "fire",
"value": 6.399999978020787
}
},
"treeData": {
"202642": {
"id": 202642,
"type": "skill",
"root": true,
"name": "星火",
"levelReq": 0,
"desc": "施放攻击后,有<nobr>50.0%</nobr>的基础概率使敌方目标陷入灼烧状态,持续<nobr>2</nobr>回合。<br />灼烧状态下,敌方目标每回合开始时受到等同于姬子<nobr>30.0%</nobr>攻击力的<span style=\"color:#F84F36;\">火</span>属性持续伤害。",
"desc": "施放攻击后,有<nobr>50.0%</nobr>的基础概率使敌方目标陷入灼烧状态,持续<nobr>2</nobr>回合。<br />灼烧状态下,敌方目标每回合开始时受到等同于姬子<nobr>30.0%</nobr>攻击力的<span>火</span>属性持续伤害。",
"cost": {
"29328": 5000,
"635675": 3,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 707 KiB

After

Width:  |  Height:  |  Size: 358 KiB

View File

@ -440,6 +440,48 @@
}
},
"tree": {
"1105201": {
"key": "hp",
"value": 4.00000000372529
},
"1105202": {
"key": "effDef",
"value": 4.00000000372529
},
"1105203": {
"key": "hp",
"value": 4.00000000372529
},
"1105204": {
"key": "def",
"value": 5.000000004656613
},
"1105205": {
"key": "hp",
"value": 6.0000000055879354
},
"1105206": {
"key": "effDef",
"value": 6.0000000055879354
},
"1105207": {
"key": "hp",
"value": 6.0000000055879354
},
"1105208": {
"key": "def",
"value": 7.499999972060323
},
"1105209": {
"key": "effDef",
"value": 8.00000000745058
},
"1105210": {
"key": "hp",
"value": 8.00000000745058
}
},
"treeData": {
"506326": {
"id": 506326,
"type": "buff",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 KiB

After

Width:  |  Height:  |  Size: 328 KiB

View File

@ -0,0 +1,40 @@
import { Format } from '#miao'
export const details = [{
title: '普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E-Buff加伤',
dmg: ({ talent }) => {
return {
avg: Format.percent(talent.e['伤害提高']),
type: 'text'
}
}
}, {
title: 'Q-Buff攻击力提高',
dmg: ({ talent }) => {
return {
avg: Format.percent(talent.q['攻击力提高']),
type: 'text'
}
}
}, {
title: 'Q-Buff爆伤提高',
dmg: ({ attr, calc, talent }) => {
return {
avg: Format.percent(calc(attr.cdmg) * talent.q['百分比暴伤'] / 100 + talent.q['固定暴伤']),
type: 'text'
}
}
}]
export const mainAttr = 'atk,cpct,cdmg'
export const buffs = [{
title: '行迹-军势布洛妮娅在场时我方全体造成的伤害提高10%',
check: ({ trees }) => trees[103],
data: {
dmg: 10
}
}]

View File

@ -398,6 +398,48 @@
}
},
"tree": {
"1101201": {
"key": "wind",
"value": 3.1999999890103936
},
"1101202": {
"key": "cdmg",
"value": 5.299999983981252
},
"1101203": {
"key": "wind",
"value": 3.1999999890103936
},
"1101204": {
"key": "effDef",
"value": 4.00000000372529
},
"1101205": {
"key": "wind",
"value": 4.799999948590994
},
"1101206": {
"key": "cdmg",
"value": 8.00000000745058
},
"1101207": {
"key": "wind",
"value": 4.799999948590994
},
"1101208": {
"key": "effDef",
"value": 6.0000000055879354
},
"1101209": {
"key": "cdmg",
"value": 10.699999961070716
},
"1101210": {
"key": "wind",
"value": 6.399999978020787
}
},
"treeData": {
"189034": {
"id": 189034,
"type": "buff",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 690 KiB

After

Width:  |  Height:  |  Size: 408 KiB

View File

@ -0,0 +1,43 @@
export const details = [{
title: 'A普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E战技伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['技能伤害'], 'e')
}, {
title: 'Q终结技伤害',
dmg: ({ talent }, dmg) => dmg(talent.q['技能伤害'], 'q')
}]
export const mainAttr = 'atk,cpct,cdmg,speed'
export const buffs = [{
title: '希儿天赋:击杀敌人增幅状态提高伤害[dmg]%',
data: {
dmg: ({ talent }) => talent.t['伤害提高'] * 100
}
}, {
title: '希儿战技释放战技后速度提高25%',
maxCons: 1,
data: {
speedPct: 25
}
}, {
title: '希儿1命对生命小于80%的敌人造成伤害时暴击率提高15%',
cons: 1,
data: {
cpct: 15
}
}, {
title: '希儿2命释放战技后2层Buff速度提高50%',
cons: 2,
data: {
speedPct: 50
}
}, {
title: '行迹-夜行抗性穿透提高20',
tree: 2,
data: {
kx: 20
}
}]

View File

@ -356,6 +356,48 @@
}
},
"tree": {
"1102201": {
"key": "atk",
"value": 4.00000000372529
},
"1102202": {
"key": "cdmg",
"value": 5.299999983981252
},
"1102203": {
"key": "atk",
"value": 4.00000000372529
},
"1102204": {
"key": "def",
"value": 5.000000004656613
},
"1102205": {
"key": "atk",
"value": 6.0000000055879354
},
"1102206": {
"key": "cdmg",
"value": 8.00000000745058
},
"1102207": {
"key": "atk",
"value": 6.0000000055879354
},
"1102208": {
"key": "def",
"value": 7.499999972060323
},
"1102209": {
"key": "cdmg",
"value": 10.699999961070716
},
"1102210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"310962": {
"id": 310962,
"type": "skill",
@ -397,7 +439,7 @@
"root": true,
"name": "割裂",
"levelReq": 0,
"desc": "增幅状态下希儿的<span style=\"color:#7788ff;\">量子</span>抗性穿透提高<nobr>20.0%</nobr>。",
"desc": "增幅状态下希儿的<span>量子</span>抗性穿透提高<nobr>20.0%</nobr>。",
"cost": {
"29328": 20000,
"125435": 1,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 802 KiB

After

Width:  |  Height:  |  Size: 477 KiB

View File

@ -398,6 +398,48 @@
}
},
"tree": {
"1103201": {
"key": "cpct",
"value": 2.699999953620136
},
"1103202": {
"key": "effPct",
"value": 4.00000000372529
},
"1103203": {
"key": "cpct",
"value": 2.699999953620136
},
"1103204": {
"key": "effDef",
"value": 4.00000000372529
},
"1103205": {
"key": "cpct",
"value": 4.00000000372529
},
"1103206": {
"key": "effPct",
"value": 6.0000000055879354
},
"1103207": {
"key": "cpct",
"value": 4.00000000372529
},
"1103208": {
"key": "effDef",
"value": 6.0000000055879354
},
"1103209": {
"key": "effPct",
"value": 8.00000000745058
},
"1103210": {
"key": "cpct",
"value": 5.299999983981252
}
},
"treeData": {
"514036": {
"id": 514036,
"type": "buff",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 639 KiB

After

Width:  |  Height:  |  Size: 382 KiB

View File

@ -0,0 +1,38 @@
export const details = [{
title: 'A普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E战技伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['技能伤害'], 'e')
}, {
title: 'Q终结技伤害',
dmg: ({ talent }, dmg) => dmg(talent.q['技能伤害'], 'q')
}]
export const mainAttr = 'atk,cpct,cdmg'
export const buffs = [{
title: '彦卿天赋:智剑连心提高[cpct]%暴击率和[cdmg]%爆伤',
data: {
cpct: ({ talent }) => talent.t['暴击率提高'] * 100,
cdmg: ({ talent }) => talent.t['爆伤提高'] * 100
}
}, {
title: '彦卿Q释放终结技提高60%暴击率,智剑连心提高爆伤[qCdmg]%',
data: {
qCpct: 60,
qCdmg: ({ talent }) => talent.q['暴伤提高'] * 100
}
}, {
title: '彦卿4命生命值大于80%时提高12%的冰抗穿透',
cons: 4,
data: {
kx: 12
}
}, {
title: '行迹-轻吕触发暴击时速度提高10%',
tree: 3,
data: {
speedPct: 10
}
}]

View File

@ -197,7 +197,7 @@
]
},
{
"name": "技能伤害",
"name": "追加攻击概率",
"isSame": false,
"values": [
0.5,
@ -461,6 +461,48 @@
}
},
"tree": {
"1209201": {
"key": "atk",
"value": 4.00000000372529
},
"1209202": {
"key": "ice",
"value": 3.1999999890103936
},
"1209203": {
"key": "atk",
"value": 4.00000000372529
},
"1209204": {
"key": "hp",
"value": 4.00000000372529
},
"1209205": {
"key": "atk",
"value": 6.0000000055879354
},
"1209206": {
"key": "ice",
"value": 4.799999948590994
},
"1209207": {
"key": "atk",
"value": 6.0000000055879354
},
"1209208": {
"key": "hp",
"value": 6.0000000055879354
},
"1209209": {
"key": "ice",
"value": 6.399999978020787
},
"1209210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"84865": {
"id": 84865,
"type": "buff",
@ -482,7 +524,7 @@
"root": true,
"name": "颁冰",
"levelReq": 0,
"desc": "施放攻击后,对携带<span style=\"color:#47C7FD;\">冰</span>属性弱点的敌方目标造成等同于彦卿<nobr>30.0%</nobr>攻击力的<span style=\"color:#47C7FD;\">冰</span>属性附加伤害。",
"desc": "施放攻击后,对携带<span>冰</span>属性弱点的敌方目标造成等同于彦卿<nobr>30.0%</nobr>攻击力的<span>冰</span>属性附加伤害。",
"cost": {
"29328": 5000,
"270195": 1,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 874 KiB

After

Width:  |  Height:  |  Size: 545 KiB

View File

@ -0,0 +1,43 @@
export const details = [{
title: 'A普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E战技伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['技能伤害'], 'e')
}, {
title: 'Q终结技伤害',
dmg: ({ talent }, dmg) => dmg(talent.q['技能伤害'], 'q')
}, {
title: '10层神君单体伤害',
dmg: ({ talent }, dmg) => dmg(talent.t['技能伤害'] * 10, 'a3')
}]
export const mainAttr = 'atk,cpct,cdmg,speed'
export const buffs = [{
title: '景元2命神君行动后普攻战技及终结技的伤害提高20%',
cons: 2,
data: {
aDmg: 20,
eDmg: 20,
qDmg: 20
}
}, {
title: '景元6命神君会使目标陷入易伤状态使伤害提高12%最多3层',
cons: 6,
data: {
a3Dmg: (12 + 12 * 2 + 12 * 3 * 7) / 10
}
}, {
title: '行迹-破阵攻击段数大于等于6段则其下回合的暴击伤害提高25%',
tree: 1,
data: {
a3Cdmg: 25
}
}, {
title: '行迹-遣将施放战技后暴击率提升10%',
tree: 3,
data: {
cpct: 10
}
}]

View File

@ -6,7 +6,6 @@
"star": 5,
"elem": "雷",
"allegiance": "仙舟「罗浮」",
"weapon": "智识",
"sp": 130,
"desc": "仙舟联盟帝弓七天将之一,负责节制罗浮云骑军的「神策将军」。 师从前代「罗浮」剑首,但并不显名于武力。",
"cncv": "孙晔",
@ -356,6 +355,48 @@
}
},
"tree": {
"1204201": {
"key": "atk",
"value": 4.00000000372529
},
"1204202": {
"key": "cpct",
"value": 2.699999953620136
},
"1204203": {
"key": "atk",
"value": 4.00000000372529
},
"1204204": {
"key": "def",
"value": 5.000000004656613
},
"1204205": {
"key": "atk",
"value": 6.0000000055879354
},
"1204206": {
"key": "cpct",
"value": 4.00000000372529
},
"1204207": {
"key": "atk",
"value": 6.0000000055879354
},
"1204208": {
"key": "def",
"value": 7.499999972060323
},
"1204209": {
"key": "cpct",
"value": 5.299999983981252
},
"1204210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"56195": {
"id": 56195,
"type": "skill",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 621 KiB

After

Width:  |  Height:  |  Size: 348 KiB

View File

@ -0,0 +1,23 @@
export const details = [{
title: '普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: '战技伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['技能伤害'], 'e')
}, {
title: 'Q护盾量',
dmg: ({ attr, calc, talent }, { shield }) => shield(calc(attr.def) * talent.q['百分比防御力'] + talent.q['固定数值'])
}, {
title: '秘技护盾量',
dmg: ({ attr, calc, talent }, { shield }) => shield(calc(attr.def) * 0.24 + 150)
}]
export const mainAttr = 'atk,cpct,cdmg,def'
export const buffs = [{
title: '行迹-战意:基于防御值提高攻击力[atkPlus]',
tree: 3,
data: {
atkPlus: ({ calc, attr }) => calc(attr.def) * 0.35
}
}]

View File

@ -398,6 +398,48 @@
}
},
"tree": {
"1104201": {
"key": "ice",
"value": 3.1999999890103936
},
"1104202": {
"key": "effDef",
"value": 4.00000000372529
},
"1104203": {
"key": "ice",
"value": 3.1999999890103936
},
"1104204": {
"key": "def",
"value": 5.000000004656613
},
"1104205": {
"key": "ice",
"value": 4.799999948590994
},
"1104206": {
"key": "effDef",
"value": 6.0000000055879354
},
"1104207": {
"key": "ice",
"value": 4.799999948590994
},
"1104208": {
"key": "def",
"value": 7.499999972060323
},
"1104209": {
"key": "effDef",
"value": 8.00000000745058
},
"1104210": {
"key": "ice",
"value": 6.399999978020787
}
},
"treeData": {
"303252": {
"id": 303252,
"type": "skill",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 507 KiB

After

Width:  |  Height:  |  Size: 327 KiB

View File

@ -377,13 +377,55 @@
}
},
"tree": {
"1108201": {
"key": "atk",
"value": 4.00000000372529
},
"1108202": {
"key": "effPct",
"value": 4.00000000372529
},
"1108203": {
"key": "atk",
"value": 4.00000000372529
},
"1108204": {
"key": "effDef",
"value": 4.00000000372529
},
"1108205": {
"key": "atk",
"value": 6.0000000055879354
},
"1108206": {
"key": "effPct",
"value": 6.0000000055879354
},
"1108207": {
"key": "atk",
"value": 6.0000000055879354
},
"1108208": {
"key": "effDef",
"value": 6.0000000055879354
},
"1108209": {
"key": "effPct",
"value": 8.00000000745058
},
"1108210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"285968": {
"id": 285968,
"type": "skill",
"root": true,
"name": "圈套",
"levelReq": 0,
"desc": "天赋使敌方陷入<span style=\"color:#00FF9C;\">风</span>化状态的持续时间延长<nobr>1</nobr>回合。",
"desc": "天赋使敌方陷入<span>风</span>化状态的持续时间延长<nobr>1</nobr>回合。",
"cost": {
"29328": 4000,
"270195": 1,
@ -400,7 +442,7 @@
"root": true,
"name": "加料",
"levelReq": 0,
"desc": "<span style=\"color:#00FF9C;\">风</span>化状态下的敌方目标对桑博造成的伤害降低<nobr>15.0%</nobr>。",
"desc": "<span>风</span>化状态下的敌方目标对桑博造成的伤害降低<nobr>15.0%</nobr>。",
"cost": {
"29328": 128000,
"125435": 1,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 KiB

After

Width:  |  Height:  |  Size: 338 KiB

View File

@ -0,0 +1,30 @@
export const details = [{
title: '普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E战技主目标伤害',
dmg: ({ talent }, dmg) => dmg(talent.e['技能伤害'], 'e')
}, {
title: 'Q终结技伤害',
dmg: ({ talent }, dmg) => dmg(talent.q['技能伤害'], 'q')
}, {
title: '天赋附加伤害',
dmg: ({ talent }, dmg) => dmg(talent.t['附加伤害'], 't')
}]
export const mainAttr = 'atk,cpct,cdmg'
export const buffs = [{
title: '行迹-惩戒施放终结技提高敌人受到伤害12%',
tree: 1,
data: {
dmg: 12
}
},
{
title: '行迹-裁决弱点击破的敌方目标造成的伤害提高20%',
tree: 3,
data: {
dmg: 20
}
}]

View File

@ -398,6 +398,48 @@
}
},
"tree": {
"1004201": {
"key": "atk",
"value": 4.00000000372529
},
"1004202": {
"key": "imaginary",
"value": 3.1999999890103936
},
"1004203": {
"key": "atk",
"value": 4.00000000372529
},
"1004204": {
"key": "effDef",
"value": 4.00000000372529
},
"1004205": {
"key": "atk",
"value": 6.0000000055879354
},
"1004206": {
"key": "imaginary",
"value": 4.799999948590994
},
"1004207": {
"key": "atk",
"value": 6.0000000055879354
},
"1004208": {
"key": "effDef",
"value": 6.0000000055879354
},
"1004209": {
"key": "imaginary",
"value": 6.399999978020787
},
"1004210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"149174": {
"id": 149174,
"type": "buff",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 KiB

After

Width:  |  Height:  |  Size: 389 KiB

View File

@ -0,0 +1,35 @@
export const details = [{
title: '普攻伤害',
dmg: ({ talent }, dmg) => dmg(talent.a['技能伤害'], 'a')
}, {
title: 'E主目标生命恢复',
dmg: ({ calc, attr, talent }, { heal }) => heal(calc(attr.hp) * talent.e['百分比生命'] + talent.e['固定值'])
}, {
title: 'Q生命恢复',
dmg: ({ calc, attr, talent }, { heal }) => heal(calc(attr.hp) * talent.q['百分比生命'] + talent.q['固定值'])
}, {
title: '天赋生息恢复',
dmg: ({ calc, attr, talent }, { heal }) => heal(calc(attr.hp) * talent.t['生息·百分比生命'] + talent.t['生息·固定值'])
}]
export const mainAttr = 'atk,cpct,cdmg,hp'
export const buffs = [{
title: '白露2命释放终结技后治疗提高15%',
cons: 2,
data: {
heal: 15
}
}, {
title: '希儿2命释放战技后2层Buff速度提高50%',
cons: 2,
data: {
speedPct: 50
}
}, {
title: '行迹-夜行抗性穿透提高20',
tree: 2,
data: {
kx: 20
}
}]

View File

@ -461,6 +461,48 @@
}
},
"tree": {
"1211201": {
"key": "hp",
"value": 4.00000000372529
},
"1211202": {
"key": "def",
"value": 5.000000004656613
},
"1211203": {
"key": "hp",
"value": 4.00000000372529
},
"1211204": {
"key": "effDef",
"value": 4.00000000372529
},
"1211205": {
"key": "hp",
"value": 6.0000000055879354
},
"1211206": {
"key": "def",
"value": 7.499999972060323
},
"1211207": {
"key": "hp",
"value": 6.0000000055879354
},
"1211208": {
"key": "effDef",
"value": 6.0000000055879354
},
"1211209": {
"key": "def",
"value": 10.000000009313226
},
"1211210": {
"key": "hp",
"value": 8.00000000745058
}
},
"treeData": {
"671251": {
"id": 671251,
"type": "skill",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 KiB

After

Width:  |  Height:  |  Size: 410 KiB

View File

@ -376,6 +376,48 @@
}
},
"tree": {
"1206201": {
"key": "atk",
"value": 4.00000000372529
},
"1206202": {
"key": "hp",
"value": 4.00000000372529
},
"1206203": {
"key": "atk",
"value": 4.00000000372529
},
"1206204": {
"key": "def",
"value": 5.000000004656613
},
"1206205": {
"key": "atk",
"value": 6.0000000055879354
},
"1206206": {
"key": "hp",
"value": 6.0000000055879354
},
"1206207": {
"key": "atk",
"value": 6.0000000055879354
},
"1206208": {
"key": "def",
"value": 7.499999972060323
},
"1206209": {
"key": "hp",
"value": 8.00000000745058
},
"1206210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"614646": {
"id": 614646,
"type": "buff",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 727 KiB

After

Width:  |  Height:  |  Size: 424 KiB

View File

@ -395,6 +395,48 @@
}
},
"tree": {
"1203201": {
"key": "atk",
"value": 4.00000000372529
},
"1203202": {
"key": "hp",
"value": 4.00000000372529
},
"1203203": {
"key": "atk",
"value": 4.00000000372529
},
"1203204": {
"key": "def",
"value": 5.000000004656613
},
"1203205": {
"key": "atk",
"value": 6.0000000055879354
},
"1203206": {
"key": "hp",
"value": 6.0000000055879354
},
"1203207": {
"key": "atk",
"value": 6.0000000055879354
},
"1203208": {
"key": "def",
"value": 7.499999972060323
},
"1203209": {
"key": "hp",
"value": 8.00000000745058
},
"1203210": {
"key": "atk",
"value": 8.00000000745058
}
},
"treeData": {
"343112": {
"id": 343112,
"type": "skill",

Some files were not shown because too many files have changed in this diff Show More